/spring-test-smart-context

Improving Spring Boot test efficiency

Primary LanguageJavaApache License 2.0Apache-2.0

Improving Spring Boot Test efficiency

Problem statement and solution

The full presentation is available here: https://www.youtube.com/watch?v=_Vci_5nr8R0 , it explains the problem and the suggested solution.

Spring test framework creates an application context according to test class configuration. The context is cached and reused for all subsequent tests. If there is an existing context with the same configuration, it will be reused. Otherwise, the new context will be created. This is a very efficient and flexible approach, but it has a drawback: eventually this may lead to out of memory errors if the number of unique configurations is too high and context has a lot of heavyweight beans like TestContainers. In many cases simple static bean definition can help, but this project suggests another approach: reordering test classes and eager context cleanup.

Supported versions

Java 8+

Spring Boot 2.4+, 3.x

TestNG 7.0.0+

JUnit 4 (via JUnit 5 junit-vintage-engine)

JUnit 5 Jupiter

Gradle Enterprise Maven Extension (test execution caching) correctly supports changed behaviour

Limitations

At the moment only single thread test execution per module is supported.

How to use

Add maven dependency (not yet available in maven central):

<dependency>
    <groupId>com.github.seregamorph</groupId>
    <artifactId>spring-test-smart-context</artifactId>
    <version>0.2-SNAPSHOT</version>
    <scope>test</scope>
</dependency>

Or Gradle dependency:

testImplementation("com.github.seregamorph:spring-test-smart-context:0.2-SNAPSHOT")

For projects with TestNG tests this will automatically setup SmartDirtiesSuiteListener which will reorder test classes and prepare the list of last test class per context configuration. The integration test classes should add SmartDirtiesContextTestExecutionListener:

@TestExecutionListeners(SmartDirtiesContextTestExecutionListener.class)

Note: the annotation is inherited, so it makes sense to annotate the base test class or use AbstractTestNGSpringIntegrationTest parent.