Calling controller from junit test - java

How can I call a spring annotated controller from a JUnit test, in a way so that spring comes into play with binding and all, but without making a http request (just mocking out the request object)? It has to include the whole shebang from the controller and down, with JPA and database and all. We are also using EJB, so maybe a bean can do this for me?
The reason for this, is that I would like to have some automatic tests that tests performance of specific controller calls, but without the client and network traffic.
Thank you

There's a section in the Spring reference about Unit-testing Spring MVC.
Here's the relevant excerpt:
Unit testing Spring MVC Controllers
To test your Spring MVC Controllers, use
ModelAndViewAssert combined with
MockHttpServletRequest,
MockHttpSession, and so on from the
org.springframework.mock.web package.
Reference:
org.springframework.mock.web
package summary
ModelAndViewAssert javadoc

You can specify a test-specific spring context for your unit test like this:
#ContextConfiguration(locations = "classpath:spring/ITestAssembly.xml")
You can then make this context use a mock or embedded data source instead of the real database.

Related

Springboot Integration Test - Unwanted Mocks

I am trying to write integration test for SpringBoot application. code looks something like below
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {Application.class, MyTestConfig.class})
#ActiveProfile("test")
class MyIntegrationTest {
#Autowire
ServiceInterface serviceA;
}
I noticed that applicationContext loads some of the service beans as Mockito mocked object which really defeats the purpose of Integration test as it does not execute some of the code. Can anyone suggest what could be wrong here. Please note that some of the services being autowired correctly but some are being mocked. I do not see any logical reason why they behaves differently since they are implemented same way. I am using spring boot 2.0.3
Already tried.
Removed MyTestConfig.class but problem remains same. Even if I use #SpringBootTest(classes = {Application.class, MyProblematicServiceImpl.class}), It still returns mocked object wherever it is autowired. MyProblematicServiceImpl is empty class annotated with #Service.
Looking at the docs, if you set the webEnvironment setting on the SpringBootTest annotation to something other than MOCK, the default, then it will start up a real web environment.
Promoting from the comments, so it’s answered.
The Application results in a component scan, which is picking up a test config you have. You may have to exclude some test configurations.
Spring Boot provides #TestConfiguration to solve this issue.

Integration tests of Spring application

I am trying to implement integration tests for my Tomcat application, but my issue is that the application is launched separately from the tests so the tests cannot access the application context and neither the database.
My idea is running the tests "within" the running application, so I can #Autowire EntityManager and check for instance the state of the database during testing or even create database entities for testing.
My only idea of doing this is to actually run the application programmatically from the tests as ClassPathXmlApplicationContext("applicationContext.xml") and the access the Context. This would work, but it would be very hard for debugging as we wouldn't be able to use Hotswapping during the testing. Also I guess the server would be stopped as soon as the tests would end. I guess that is not the best and correct solution.
EDIT:
My question was probably unclear, so I will try to clarify.
I have a Tomcat application with Spring and Hibernate. The Spring beans and Hibernate database connection is initialised when the Tomcat application is started. The issue is how to run the tests of the active Spring beans from methods annotated with #Test in src/test/java which are started separately.
Consider this class:
#Component
class MyRepository {
#Autowired
EntityManager em;
#Transactional
public void myMethod(MyEntity entity) {
// do some job with entity
...
em.flush();
}
}
This class will be initialised with Tomcat as a MyRepository bean.
To test it, I cannot just call new MyRepository().myMethod(...) - I need to access the bean. The issue is accessing the bean from the #Test method:
#Test
void testMyRepository() {
Item item = ...
// then use the repository to handle the entity
context.getBean(MyRepository.class).myMethod(item);
// then assert the state of the database
context.getBean(EntityManager.class).find(Item.class, ...) ...
}
I can probably get the context in the initialisation of the tests with
ApplicationContext context = ClassPathXmlApplicationContext("applicationContext.xml");
But it would mean launching the whole application each time the tests are started. The better solution would be if the application could run separately from the tests.
Hope my problem is more clear now.
I would suggest you to use the SpringRunner to start the Spring application context and perform your tests on that running instance. You can customize the context the way it doesn't contain parts you don't want to tests and you can create mocks for components that require some external resources (REST clients and such). Take a look at the Spring docs or Spring Boot docs.
If multiple tests use the same Spring context configuration, the context is started just once and reused. So it's good to have it's configuration in a parent class of your tests. You can autowire any Spring bean into your test and test it.
You can use an in-memory database (such as H2) instead of a production one, so your tests are not dependent on an external infrastructure. To initialize the database, use tools like Flyway or Liquibase. To clear the database before each test, you can use the #Sql annotation.
You can find many examples of projects with such tests, for example my own demo.
If you want to test an external system, I would suggest something like JMeter.
Unfortunately you cant mirror your classes and use them in your tests. Thats a big disadvantage of web services. They always depend on user / machine interaction. With a lot of effort you can extract the functionality of the essential classes or methods and construct test scenarios etc. with jUnit.
The Overview of your possibilities:
special drivers and placeholders
you can use a logger with detailed log-level and file output. Then you created scenarios with the expected result and compare it with your log files.
Capture replay tools. They record your exection and replay them for monitoring.
I can also recommend using Selenium for the frontend tests.
Hope it helped.

How do I unit test a Spring 4 DAO method with Spring Security?

I had some unit tests for the DAO layer of a Spring 4 MVC application. Then I added Spring Security to certain methods in my controllers, and the DAO's they use.
I figured out how to make the #WithMockUser annotation work in the controller tests, but I'm stumped on the DAO tests. The exception I get on every dao test is:
java.lang.IllegalStateException: Failed to load ApplicationContext
....
Caused by: java.lang.IllegalArgumentException: An AuthenticationManager is required
I have these annoations at the start of the DaoTest:
#TestExecutionListeners({ WithSecurityContextTestExecutionListener.class })
#ContextConfiguration(classes = DaoConfig.class)
The #ContextConfiguration is the same as in the actual code; I've suggestions to make it different, but nothing concrete. How do I unravel this? I'm also hoping there's a way to do it without using org.springframework.web.* or org.springframework.test.web.* classes, since this should be 'underneath' the whole web tier.
In general it's not a good idea to test too many things at once. With a unit test you want to test one thing and one thing only. My advice would be to not have Spring Security load at all when your DAO unit tests run. You should be able to make your DAO unit test class extend some kind of AbstractTest class that loads a separate applicationContext-test.xml or Java Config that does not include Spring Security at all. That should allow your unit tests to not have to pierce some security layer the unit test really shouldn't care about. Unless, that is, you're in fact attempting integration testing instead. That would be another situation entirely.... Hope this helps.

Testing #MessageMapping WebSocket methods of Spring MVC controllers

I am currently experimenting with the support for WebSockets added in Spring 4.0, as described in this guide. As demonstrated in the guide, methods annotated with #MessageMapping can be added to any Spring MVC controller, which may also contain #RequestMapping methods.
The spring-test module has support for writing integration tests for #RequestMapping methods (as described here) in a very simple and fluid way:
#Test
public void getAccount() throws Exception {
this.mockMvc.perform(get("/accounts/1").accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json"))
.andExpect(jsonPath("$.name").value("Lee"));
}
Is there similar support for testing #MessageMapping methods using WebSockets? I have not found anything in any of the Spring modules, and none of the WebSocket guides contain any tests. If not, would I need to actually deploy the application and use a WebSocketConnectionManager to connect a test client? Or is there some API I can build on from spring-test?
This sample project contains such a small test client, but I would prefer to integrate this into the actual tests without requiring me to deploy the application and hardcode the deployed path in the tests.
There is nothing like Spring MVC Test for #MessageMapping methods yet. However, a similar approach to testing should be possible even without the fluent API. There is a ticket in JIRA (see https://jira.spring.io/browse/SPR-11266) to provide documentation so watch that ticket for more details in the very near future.

Good Way to Test Spring Services With Method Level Annotaions

I have a Spring service I want to test that uses the #Validated annotation on one of its method parameters. I would like to test it in the Spring container, but I am not sure if that is the best way. If testing in the container is the best solution for my situation, I would like to know how to run it in the container without loading my complete configuration. Any thoughts?
I ended up using the Spring Test Framework. I am using the standalone and the web application context of the mock MVC to test my annotations.
Spring 3.2.4 Test Framework
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/testing.html
Configuration Example
http://www.petrikainulainen.net/programming/spring-framework/unit-testing-of-spring-mvc-controllers-configuration/

Categories