Testcontainers
Real databases, brokers and services in Docker containers, started by your tests.
What it is
Testcontainers is a Java library that provides lightweight, disposable Docker containers for running integration tests. It allows developers to test against databases, message brokers, or any containerized service in a reproducible way.
Testcontainers allows developers to spin up Docker containers for databases, message queues, or other services during test execution. It supports JUnit 5 extensions, lifecycle management, reusable containers, and pre-configured modules for common services like PostgreSQL, MySQL, Kafka, and Redis.
- Licence
- MIT
- Best known for
- Ending the 'works on H2, fails on Postgres' class of bug
When to use it
The question documentation cannot answer for you — because it cannot recommend something else.
Reach for it when
- Integration tests that should run against the actual database, not an in-memory substitute
- You have been burned by H2 behaving differently from PostgreSQL in production
Look elsewhere when
- Docker is unavailable in your CI environment
- Fast unit tests — container startup costs seconds, so keep these tests in a separate suite
Installation
Add org.testcontainers:testcontainers dependency in pom.xmlGetting started
The smallest useful thing you can do with it, and what each part means.
import org.testcontainers.containers.PostgreSQLContainer;
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15.3")
.withDatabaseName("testdb")
.withUsername("user")
.withPassword("password");
postgres.start();String jdbcUrl = postgres.getJdbcUrl();
String username = postgres.getUsername();
String password = postgres.getPassword();
Connection conn = DriverManager.getConnection(jdbcUrl, username, password);Advanced usage
Where the library earns its place over a simpler alternative.
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@Testcontainers
public class MyDatabaseTest {
@Container
public static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15.3");
@Test
void testDatabaseConnection() {
assertNotNull(postgres.getJdbcUrl());
}
}postgres.withReuse(true);
// container can be reused across multiple test runs for faster executionimport org.testcontainers.containers.KafkaContainer;
KafkaContainer kafka = new KafkaContainer("confluentinc/cp-kafka:7.6.1");
kafka.start();postgres.withInitScript("init.sql").withExposedPorts(5432);Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Docker not found
- Ensure Docker is installed and running on your system before running Testcontainers.
- Container startup timeout
- Increase startup timeout or verify the Docker image is available and compatible.
- Networking issues connecting to container
- Check Docker network configuration and exposed ports; ensure the test code uses the container's dynamic ports.
Best practices
- Use `@Testcontainers` and `@Container` annotations for automatic lifecycle management.
- Prefer lightweight containers for faster test execution.
- Reuse containers when possible to reduce startup time.
- Externalize configuration and credentials to environment variables for security.
- Combine Testcontainers with JUnit 5 for seamless integration testing in CI/CD pipelines.
Alternatives
Comparable options, and the reason you would pick one over the other.
Background
Why it exists, and what it was reacting to.
Testcontainers was created to simplify integration testing by providing real, isolated environments using Docker containers. It eliminates the need for complex local setup and ensures tests run consistently across different machines and CI environments.
