Careeroza
Testcontainers
Real PostgreSQL in Every Test Run
Testcontainers starts a throwaway Docker container for the test run. Spring Boot 3.1+ wires it in with @ServiceConnection, no URL properties needed.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>The Test
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // keep our DataSource
@Testcontainers
class OrderRepositoryIT {
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
@Autowired OrderRepository orders;
@Autowired TestEntityManager tem;
@Test
void flywayMigrationsMatchTheEntities() {
// Flyway ran all V*.sql scripts; ddl-auto=validate passed, or the context would not start
assertThat(orders.count()).isZero();
}
@Test
void pickBatchSkipsLockedRows() {
// uses FOR UPDATE SKIP LOCKED: only testable on a real database
...
}
}Run
./mvnw test -Dtest=OrderRepositoryITExample output
Creating container for image: postgres:16-alpine Container postgres:16-alpine is starting: 3f2a9c... Container postgres:16-alpine started in PT1.9S Flyway: Successfully applied 18 migrations to schema "public", now at version v18 HHH000490: Using JtaPlatform implementation: [NoJtaPlatform] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 6.41 s
Faster Runs
- Share one container across test classes: put it in a base class or a
@TestConfigurationwith a@Bean @ServiceConnectionmethod, and import that config. - Spring caches the application context between test classes with the same configuration, so the container starts once per run.
- Locally,
.withReuse(true)plustestcontainers.reuse.enable=truein~/.testcontainers.propertieskeeps the container between runs. - CI needs Docker: GitHub Actions
ubuntu-latestrunners have it.