How to Recreate Database Before Each Test in Spring

Dec 01, 2025 · Programming · 10 views · 7.8

Keywords: Spring Testing | Database Recreation | @DirtiesContext

Abstract: This article explores how to ensure database recreation before each test method in Spring Boot applications, addressing data pollution issues between tests. By analyzing the ClassMode configuration of @DirtiesContext annotation and combining it with @AutoConfigureTestDatabase, a complete solution is provided. The article explains Spring test context management mechanisms in detail and offers practical code examples to help developers build reliable testing environments.

Problem Background and Challenges

In Spring Boot application development, testing is crucial for ensuring code quality. However, when tests involve database operations, a common issue is data pollution between test methods. Developers typically expect each test method to execute in a clean database environment, but Spring's default behavior may not meet this expectation.

As described in the problem, the developer configured an H2 database in application.properties:

spring.datasource.url=jdbc:h2:tcp://localhost/~/pdk
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver

Upon application startup, the database is automatically recreated, but during test execution, it is only recreated once. Since test execution order is non-deterministic, this leads to unreliable test results. The developer attempted to use the @DirtiesContext annotation but did not achieve the desired effect.

Core Solution: ClassMode Configuration of @DirtiesContext

The Spring testing framework provides the @DirtiesContext annotation to mark that the application context needs to be reloaded after test method or class execution. By default, when used at the class level, this annotation marks the context as "dirty" after the entire test class, but does not recreate the database before each test method.

To recreate the database before each test method, the classMode attribute must be explicitly set:

@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)

According to the Spring documentation, @DirtiesContext can be used as both a class-level and method-level annotation. When ClassMode is set to BEFORE_EACH_TEST_METHOD, the context is marked as dirty before each test method, triggering database recreation.

An example application in a test class is as follows:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApp.class)
@WebIntegrationTest
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
public class WebControllersTest {
    // Test methods
}

This configuration ensures each test method executes in a fresh database context, avoiding data residue issues.

Advanced Issues and Supplementary Solutions

In some cases, using only @DirtiesContext may be insufficient. For example, in Spring Boot 2.2.0, developers might encounter JDBC syntax errors, such as exceptions for existing constraints:

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FKEFFD698EA2E75FXEERWBO8IUT" already exists; SQL statement: alter table foo add constraint FKeffd698ea2e75fxeerwbo8iut foreign key (bar) references bar [90045-200]

This occurs because the database recreation may not fully clean up table structures. To address this, the @AutoConfigureTestDatabase annotation can be combined, which is part of the spring-boot-test-autoconfigure module.

@AutoConfigureTestDatabase allows configuration of test database replacement behavior. By setting replace = Replace.ANY, it ensures an embedded database replaces any configured data source, avoiding constraint conflicts.

A complete example code is as follows:

import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
@AutoConfigureTestDatabase(replace = Replace.ANY)
public class FooRepositoryTest {
    // Test methods
}

This combined approach not only ensures database recreation before each test method but also handles potential database constraint issues, providing a more robust testing environment.

Implementation Principles and Best Practices

Understanding how @DirtiesContext works helps in its effective application. When the context is marked as dirty, Spring closes the current application context and recreates a new one. This includes reinitializing all beans, including data sources and related database configurations. Thus, the database is recreated as the context refreshes.

However, frequent context recreation may incur performance overhead. In large test suites, this can significantly increase test execution time. Therefore, it is recommended to use the BEFORE_EACH_TEST_METHOD mode only when necessary, such as when test methods modify database states that could affect other tests.

For tests that do not require database state isolation, consider using transaction rollback strategies. With the @Transactional annotation, each test method can execute within a transaction and automatically roll back after completion, keeping the database state unchanged. But this is not suitable for test scenarios requiring committed changes.

Another best practice is to use specific test profiles. With the @ActiveProfiles("test") annotation, configurations designed for testing environments can be loaded, such as using an in-memory database instead of a production one. This further isolates tests from production environments.

In code, ensure database initialization logic (e.g., the afterPropertiesSet method of InitializingBean) executes correctly during context refresh. If initialization logic depends on specific states, adjustments may be needed to adapt to the testing environment.

Conclusion

To recreate the database before each test method in Spring testing, the core lies in correctly configuring the ClassMode attribute of the @DirtiesContext annotation. By setting it to BEFORE_EACH_TEST_METHOD, database recreation is ensured with context refresh. For more complex cases, combining @AutoConfigureTestDatabase can resolve constraint conflicts and other issues.

Developers should balance performance and isolation based on test requirements, choosing appropriate strategies. By understanding Spring testing framework mechanisms and applying the solutions provided in this article, reliable and efficient testing environments can be built, enhancing code quality and maintainability.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.