Search code examples
javaspringmavenunit-testing

Slow unit testing in spring-boot application


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 from 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?


Solution

  • 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:

    • You cannot access any external components (web servers, db and so forth)
    • Unit tests run only in memory
    • They are extremely fast (particle of second).

    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.