Imagine you have one hundred spring boot test classes. When you start all of your tests, what is your intention:

  • Load application context for every class
  • Reuse the same application context

Since loading the application context takes time(it can take more than ten seconds), you would like to reuse the same application context. Spring tries to reuse context but there are some situations where spring creates a new context.

A simple way to see how many contexts your tests started is to count the number of spring logos in your console. Every time context starts to load, you can see a big spring logo in the console.

If you introduce @TestConfiguration , you must load a new context for that test class. This makes sense since when you ask for FooBean in your test where @TestConfiguration is present, you will receive bean from @TestConfiguration. In some other tests, you will receive some other bean. There is no way how to reuse the same context.

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringTest {

    @Test
    //Some test
    
    @TestConfiguration
    public static class CustomConfiguration {
        @Bean
        public FooBean fooBean() {
            return new FooBean();
        }
    }
}

Almost the same thing happens when you introduce @MockBean, context cannot be reused for obvious reasons.

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringTest {

    @MockBean
    private FooBean fooBean;
    
    @Test
    //Some test
}

If you annotate a test class or method with @DirtiesContext, for that class or method a new context must be loaded. That is the purpose of that annotation. When do people usually use this annotation? When they want to reload the cache or change some property. But the truth is that often you don’t need to reload the whole context to restart cache. Sometimes you can manually restart that cache by calling cacheManager.clearCache() or something like that.

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringTest {
    
    @Test
    @DirtiesContext
    //Some test
}

If you introduce @ActiveProfiles annotation one profile will be created for every combination of profiles. It makes sense since the test with the dev profile will have different beans loaded from the test with prod profile active

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles(profiles = {"dev","prod"})
public class SpringTest {
    
    @Test
    //Some test
}

If you set some custom property like this:

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "os=windows")
public class SpringTest {

   @Test
   ...
}

spring framework creates a new context for this class using custom property.

When you load the context, you load all the beans into the context. @Controllers, @Repositories, etc… If your tests don’t need controllers because you are writing just unit tests of domain classes or just repositories tests you can load one subset of beans. Instead of @SpringBootTest you can use: @JsonTest@DataJpaTestWebMvcTest etc…

You can find full list of slices here.

Further reading

There are more ways how to kill the performance of your tests by not reusing context. You can learn more about this topic on this here.