I'm still new to unit testing. I started to read a book about it. But one of the most important thing is that a test hast to be first (Fast,Isolated,Repeatable,Self-validating,Timely).
Okay, now I was ready for a bit of practice. But when I was building unit test in spring boot. I like to keep them separated.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = UnitTestApplication.class, loader = SpringApplicationContextLoader.class)
@WebIntegrationTest("server.port:9000")
public class FirstTestClassTest{
...
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = UnitTestApplication.class, loader = SpringApplicationContextLoader.class)
@WebIntegrationTest("server.port:9001")
public class SecondTestClassTest{
...
}
This gives me the problem that for every test class there is a new instance started of the application.
So let's say I introduce a new feature and want to test for bugs. I use mvn test form the command line. Then all the test are run but i think it will take ages for a real application with a lot of tests.
I there a way that there is only one instance started and keep the test fast but where i can keep the test in separate classes?
I'll refer your sentence:
So let's say I introduce a new feature and want to test for bugs. I use mvn test form the command line. Then all the test are run but i think it will take ages for a real application with a lot of tests.
This question you raise here is very important, so I'll try to provide an architectural point of view here without delving into technical implementation.
There are many different kinds of tests. What you're referring to is called an integration test, and not a unit test. The difference between those two that in unit tests you're testing one class and all the rest should be mocked (there are frameworks like EasyMock or Mockito for this).
Unit test has a lot of restrictions:
These tests are very helpful when it comes to testing the functionality of your classes
Now when the development of the feature is done, its time to test that the feature works in "semi-real" environment. Usually when running those, there is a database available as well as spring container. For running this kind of tests you can use spring tests extensions and use different techniques (for example, substitute one the whole application spring context with a "partial" context or override some beans with stubs or something.
Now, this difference is interesting in the context of your question because there should be many unit tests and substantially less integration tests in the application. So if you can cover something you've written with unit tests - write unit tests. It's incredibly fast by nature and you can run a lot of those (thousands) in no-time. Only if you (rarely) cannot cover your functionality in unit tests - write the integration test. This will typically relevant for code that runs against the DB for example and you would like to test whether the queries produced by the component are really valid.
So generally if you have both types of tests you should be covered and there should be not so many integration tests, so running those shouldn't be a real hassle.
One of the ways to make spring mvc tests much faster is to use MockMvcBuilders.standaloneSetup
With this setup you use not a real but a mocked application context. This setup has a very reach configuration options and in my experience, it is sufficient for most of controller tests.
That way you need to create your controller instances and inject them with mocked dependencies by hand. Here is an example of MockMvc unit test with standalone setup.
// setup beans and mockMvc
UserDAO userDAO = mock(UserDAO.class);
UserController userController = new UserController(userDAO);
MockMvc mockMvc = standaloneSetup(userController)
.setViewResolvers(new WebConfig().viewResolver())
.build();
...
// do test
mockMvc.perform(get(USERS))
.andExpect(view().name(USERS_VIEW_NAME))
.andExpect(model().attribute(TOTAL, 20))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With