autumn leaves

Image by Couleur from Pixabay

In my previous post, I’ve written about why you want to have lightning-fast tests.

The most relevant time consumer in spring↗ tests is the spring context startup.

You want to avoid or reduce this spring test startup time as much as possible.

best: no spring

If possible, don’t use spring at all in tests. Use please use plain java classes and simple mockito mocks (maybe MockInjector).

If you need to test two or three classes together, then wire them manually without using the spring framework.

second best: small spring context

If you still need spring, e.g. because you’re testing your repository class, then use a spring context as small as possible.

Option a: use “spring test slices”

With spring test slices, you do not need to start the complete context but only a small subset. There are preconfigured contexts for testing JPA, spring WebMVC and others.

You can find a good introduction to spring test slices on

Option b: write your own minimal spring context

    @ExtendWith({SpringExtension.class})
    @ContextConfiguration(classes = {MyClassTest.Config.class})
    class MyClassTest {
    
      @Configuration
      @ComponentScan(basePackages = {"<here come the packages>", "<that you need for the test>"})
      public static class Config {
    
        @Bean
        SomeDependency someDependency() {
          return new SomeDependency(); 
          // configure some dependency that is outside the declared packages above
        }
        
        @Bean
        SomeOtherDependency someOtherDependency() {
          return mock(SomeOtherDependency.class);        
          // ATTENTION: 
          // This will be the SAME INSTANCE of your mockito MOCK in all tests with this configuration!
          // spring uses singleton scope for beans by default   
        }
    
      }
    
      @Autowired
      MyClass instanceUnderTest;
    
      @Test
      void testSomething() {
         // here comes your test code
      }
    
    }

This solution comes with some downsides:

  • If you use separate contexts for every test, then spring cannot cache the context.
  • If you use mockito mocks in the config, then ALL tests using this context will share the same instance of the mockito mock, because spring uses singleton scope by default. Keep this in mind when stubbing or verifying behaviour.

third best: context caching

If you still have slow spring context setups in your test, make sure that spring can reuse the same context for different tests. Try to avoid @DirtiesContext and @MockBean.

more documentation

You can find a nice overview on spring test performance tuning on https://www.baeldung.com/spring-tests.

My next post is about how to speed up turnaround cycles on integration tests.

Any comments or suggestions? Leave an issue or a pull request!