integration-testing
📋 Copy All TestContainers Commands
📄 Generate TestContainers PDF Guide
TestContainers Cheatsheet
Installation
Prerequisites
Requirement
Version
Verification Command
Docker
Latest stable
docker --version
Java JDK
8 or higher
java -version
Maven/Gradle
Latest
mvn -v or gradle -v
Maven Dependencies
<!-- Core TestContainers -->
<dependency>
<groupId> org.testcontainers</groupId>
<artifactId> testcontainers</artifactId>
<version> 1.19.3</version>
<scope> test</scope>
</dependency>
<!-- JUnit 5 Integration -->
<dependency>
<groupId> org.testcontainers</groupId>
<artifactId> junit-jupiter</artifactId>
<version> 1.19.3</version>
<scope> test</scope>
</dependency>
<!-- Database Modules -->
<dependency>
<groupId> org.testcontainers</groupId>
<artifactId> postgresql</artifactId>
<version> 1.19.3</version>
<scope> test</scope>
</dependency>
<dependency>
<groupId> org.testcontainers</groupId>
<artifactId> mysql</artifactId>
<version> 1.19.3</version>
<scope> test</scope>
</dependency>
<dependency>
<groupId> org.testcontainers</groupId>
<artifactId> mongodb</artifactId>
<version> 1.19.3</version>
<scope> test</scope>
</dependency>
Gradle Dependencies
// Kotlin DSL
testImplementation ( "org.testcontainers:testcontainers:1.19.3" )
testImplementation ( "org.testcontainers:junit-jupiter:1.19.3" )
testImplementation ( "org.testcontainers:postgresql:1.19.3" )
testImplementation ( "org.testcontainers:mysql:1.19.3" )
testImplementation ( "org.testcontainers:kafka:1.19.3" )
// Groovy DSL
testImplementation 'org.testcontainers:testcontainers:1.19.3'
testImplementation 'org.testcontainers:junit-jupiter:1.19.3'
testImplementation 'org.testcontainers:postgresql:1.19.3'
Platform
Installation Command
Ubuntu/Debian
curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh
macOS
brew install --cask docker
Windows
Download Docker Desktop from docker.com
Linux Post-Install
sudo usermod -aG docker $USER && newgrp docker
Basic Commands
Container Lifecycle Operations
Command
Description
container.start()
Start a container instance
container.stop()
Stop and remove the container
container.isRunning()
Check if container is currently running
container.getContainerId()
Get Docker container ID
container.getDockerImageName()
Get the image name used
container.getLogs()
Retrieve all container logs as string
container.getHost()
Get host address (usually localhost)
container.getMappedPort(int)
Get host port mapped to container port
container.getExposedPorts()
List all exposed container ports
container.getContainerInfo()
Get detailed container information
Generic Container Creation
Command
Description
new GenericContainer("image:tag")
Create container from any Docker image
.withExposedPorts(port1, port2)
Expose container ports to host
.withEnv("KEY", "value")
Set environment variable
.withCommand("cmd", "arg1")
Override container command
.withLabel("key", "value")
Add Docker label to container
.withNetworkMode("host")
Set container network mode
.withPrivilegedMode()
Run container in privileged mode
.withCreateContainerCmdModifier(cmd)
Modify container creation command
.withStartupTimeout(Duration)
Set maximum startup wait time
.withReuse(true)
Enable container reuse across tests
Database Containers
Command
Description
new PostgreSQLContainer("postgres:15")
Create PostgreSQL container
new MySQLContainer("mysql:8.0")
Create MySQL container
new MongoDBContainer("mongo:6.0")
Create MongoDB container
.withDatabaseName("dbname")
Set database name
.withUsername("user")
Set database username
.withPassword("pass")
Set database password
.getJdbcUrl()
Get JDBC connection URL
.getReplicaSetUrl()
Get MongoDB replica set URL (MongoDB)
.withInitScript("init.sql")
Run SQL script on startup
.withConfigurationOverride("path")
Override database configuration
Advanced Usage
Wait Strategies
Command
Description
.waitingFor(Wait.forListeningPort())
Wait until port is listening
.waitingFor(Wait.forHttp("/health"))
Wait for HTTP endpoint to respond
.waitingFor(Wait.forLogMessage(".*ready.*", 1))
Wait for specific log message
.waitingFor(Wait.forHealthcheck())
Wait for Docker healthcheck to pass
.waitingFor(Wait.forSuccessfulCommand("cmd"))
Wait for command to succeed
.forStatusCode(200)
Specify expected HTTP status code
.forStatusCodeMatching(code -> code < 500)
Custom status code matcher
.withStartupTimeout(Duration.ofMinutes(2))
Set startup timeout duration
.withReadTimeout(Duration.ofSeconds(10))
Set HTTP read timeout
.forResponsePredicate(response -> true)
Custom response validation
File and Volume Operations
Command
Description
.withFileSystemBind("host", "container")
Bind mount host directory
.withFileSystemBind(path, target, BindMode.READ_ONLY)
Mount with specific mode
.withClasspathResourceMapping("res", "path")
Mount classpath resource
.copyFileToContainer(MountableFile, "path")
Copy file into container
.withCopyFileToContainer(file, path)
Copy file during startup
.withTmpFs(Map.of("/tmp", "rw"))
Mount tmpfs filesystem
MountableFile.forClasspathResource("file")
Reference classpath file
MountableFile.forHostPath("/path")
Reference host file system path
BindMode.READ_WRITE
Allow read and write access
BindMode.READ_ONLY
Allow only read access
Networking
Command
Description
Network.newNetwork()
Create custom Docker network
.withNetwork(network)
Attach container to network
.withNetworkAliases("alias")
Set network alias for container
.dependsOn(otherContainer)
Define container dependency
.withExtraHost("hostname", "ip")
Add entry to /etc/hosts
.getNetworkAliases()
Get all network aliases
.withAccessToHost(true)
Allow container to access host
Network.SHARED
Use shared network across tests
.withNetworkMode("bridge")
Set specific network mode
.getNetwork()
Get network container is attached to
Container Execution
Command
Description
.execInContainer("cmd", "arg1")
Execute command in running container
.execInContainer(Charset, "cmd")
Execute with specific charset
result.getStdout()
Get standard output from execution
result.getStderr()
Get standard error from execution
result.getExitCode()
Get command exit code
.copyFileFromContainer("path", consumer)
Copy file from container
.followOutput(consumer)
Stream container logs
new Slf4jLogConsumer(logger)
Log output to SLF4J logger
new ToStringConsumer()
Capture output as string
new WaitingConsumer()
Wait for specific output
JUnit 5 Integration
Command
Description
@Testcontainers
Enable TestContainers extension
@Container
Mark field as container to manage
static @Container
Share container across all tests
@DynamicPropertySource
Inject container properties
registry.add("prop", container::getUrl)
Add dynamic property
@BeforeAll
Setup containers before all tests
@AfterAll
Cleanup containers after all tests
@Nested
Group tests with shared containers
Startables.deepStart(containers).join()
Start multiple containers in parallel
.withReuse(true)
Reuse container across test runs
Configuration
TestContainers Properties
Create testcontainers.properties in src/test/resources:
# Docker host configuration
docker.host = unix:///var/run/docker.sock
# docker.host=tcp://localhost:2375
# Container reuse (requires Docker labels support)
testcontainers.reuse.enable = true
# Image pull policy
testcontainers.image.pull.policy = DefaultPullPolicy
# Ryuk container (cleanup)
testcontainers.ryuk.disabled = false
testcontainers.ryuk.container.image = testcontainers/ryuk:0.5.1
# Checks
testcontainers.checks.disable = false
Docker Compose Integration
@Container
static DockerComposeContainer environment =
new DockerComposeContainer ( new File ( "docker-compose.yml" ))
. withExposedService ( "db" , 5432 )
. withExposedService ( "redis" , 6379 )
. withLocalCompose ( true )
. withPull ( true )
. waitingFor ( "db" , Wait . forHealthcheck ());
Custom Container Configuration
public class CustomPostgreSQLContainer extends PostgreSQLContainer < CustomPostgreSQLContainer > {
private static final String IMAGE_VERSION = "postgres:15-alpine" ;
public CustomPostgreSQLContainer () {
super ( IMAGE_VERSION );
this . withDatabaseName ( "testdb" )
. withUsername ( "testuser" )
. withPassword ( "testpass" )
. withInitScript ( "init.sql" )
. withCommand ( "postgres -c max_connections=200" );
}
}
Spring Boot Integration
@SpringBootTest
@Testcontainers
class ApplicationTests {
@Container
static PostgreSQLContainer <?> postgres = new PostgreSQLContainer <> ( "postgres:15-alpine" )
. withDatabaseName ( "testdb" );
@DynamicPropertySource
static void configureProperties ( DynamicPropertyRegistry registry ) {
registry . add ( "spring.datasource.url" , postgres :: getJdbcUrl );
registry . add ( "spring.datasource.username" , postgres :: getUsername );
registry . add ( "spring.datasource.password" , postgres :: getPassword );
registry . add ( "spring.jpa.hibernate.ddl-auto" , () -> "create-drop" );
}
@Test
void contextLoads () {
// Test with real database
}
}
Common Use Cases
Use Case 1: PostgreSQL Integration Test
@Testcontainers
@SpringBootTest
class UserRepositoryTest {
@Container
static PostgreSQLContainer <?> postgres = new PostgreSQLContainer <> ( "postgres:15-alpine" )
. withDatabaseName ( "testdb" )
. withUsername ( "test" )
. withPassword ( "test" )
. withInitScript ( "schema.sql" );
@DynamicPropertySource
static void registerProperties ( DynamicPropertyRegistry registry ) {
registry . add ( "spring.datasource.url" , postgres :: getJdbcUrl );
registry . add ( "spring.datasource.username" , postgres :: getUsername );
registry . add ( "spring.datasource.password" , postgres :: getPassword );
}
@Autowired
private UserRepository userRepository ;
@Test
void shouldSaveAndFindUser () {
User user = new User ( "john@example.com" , "John Doe" );
userRepository . save ( user );
Optional < User > found = userRepository . findByEmail ( "john@example.com" );
assertTrue ( found . isPresent ());
assertEquals ( "John Doe" , found . get (). getName ());
}
}
Use Case 2: Kafka Message Processing Test
@Testcontainers
class KafkaIntegrationTest {
@Container
static KafkaContainer kafka = new KafkaContainer (
DockerImageName . parse ( "confluentinc/cp-kafka:7.5.0" )
);
@DynamicPropertySource
static void kafkaProperties ( DynamicPropertyRegistry registry ) {
registry . add ( "spring.kafka.bootstrap-servers" , kafka :: getBootstrapServers );
}
@Autowired
private KafkaTemplate < String , String > kafkaTemplate ;
@Autowired
private MessageListener messageListener ;
@Test
void shouldProcessMessage () throws Exception {
String topic = "test-topic" ;
String message = "Hello Kafka!" ;
kafkaTemplate . send ( topic , message );
// Wait for message processing
await (). atMost ( Duration . ofSeconds ( 10 ))
. until (() -> messageListener . getReceivedMessages (). size () == 1 );
assertEquals ( message , messageListener . getReceivedMessages (). get ( 0 ));
}
}
Use Case 3: Multi-Container Microservices Test
@Testcontainers
class MicroservicesIntegrationTest {
static Network network = Network . newNetwork ();
@Container
static PostgreSQLContainer <?> database = new PostgreSQLContainer <> ( "postgres:15-alpine" )
. withNetwork ( network )
. withNetworkAliases ( "database" )
. withDatabaseName ( "orders" );
@Container
static GenericContainer <?> redis = new GenericContainer <> ( "redis:7-alpine" )
. withNetwork ( network )
. withNetworkAliases ( "redis" )
. withExposedPorts ( 6379 );
@Container
static GenericContainer <?> orderService = new GenericContainer <> ( "order-service:latest" )
. withNetwork ( network )
. withExposedPorts ( 8080 )
. withEnv ( "DATABASE_URL" , "jdbc:postgresql://database:5432/orders" )
. withEnv ( "REDIS_HOST" , "redis" )
. dependsOn ( database , redis )
. waitingFor ( Wait . forHttp ( "/actuator/health" ). forStatusCode ( 200 ));
@Test
void shouldCreateOrder () {
String baseUrl = "http://" + orderService . getHost () + ":"
+ orderService . getMappedPort ( 8080 );
// Make HTTP request to order service
RestTemplate restTemplate = new RestTemplate ();
Order order = new Order ( "item-123" , 2 );
ResponseEntity < Order > response = restTemplate . postForEntity (
baseUrl + "/orders" , order , Order . class
);
assertEquals ( HttpStatus . CREATED , response . getStatusCode ());
assertNotNull ( response . getBody (). getId ());
}
}
Use Case 4: MongoDB Integration Test
@Testcontainers
@DataMongoTest
class ProductRepositoryTest {
@Container
static MongoDBContainer mongodb = new MongoDBContainer ( "mongo:6.0" )
. withExposedPorts ( 27017 );
@DynamicPropertySource
static void mongoProperties ( DynamicPropertyRegistry registry ) {
registry . add ( "spring.data.mongodb.uri" , mongodb :: getReplicaSetUrl );
}
@Autowired
private ProductRepository productRepository ;
@Test
void shouldFindProductsByCategory () {
// Insert test data
productRepository . save ( new Product ( "Laptop" , "Electronics" , 999.99 ));
productRepository . save ( new Product ( "Mouse" , "Electronics" , 29.99 ));
productRepository . save ( new Product ( "Desk" , "Furniture" , 299.99 ));
// Query by category
List < Product > electronics = productRepository . findByCategory ( "Electronics" );
assertEquals ( 2 , electronics . size ());
assertTrue ( electronics . stream ()
. allMatch ( p -> p . getCategory (). equals ( "Electronics" )));
}
}
Use Case 5: Docker Compose Test Environment
@Testcontainers
class FullStackIntegrationTest {
@Container
static DockerComposeContainer <?> environment = new DockerComposeContainer <> (
new File ( "src/test/resources/docker-compose-test.yml" )
)
. withExposedService ( "api" , 8080 ,
Wait . forHttp ( "/health" ). forStatusCode ( 200 ))
. withExposedService ( "postgres" , 5432 ,
Wait . forListeningPort ())
. withExposedService ( "redis" , 6379 )
. withLocalCompose ( true );
@Test
void shouldConnectToAllServices () {
String apiHost = environment . getServiceHost ( "api" , 8080 );
Integer apiPort = environment . getServicePort ( "api" , 8080 );
String apiUrl = "http://" + apiHost + ":" + apiPort ;
RestTemplate restTemplate = new RestTemplate ();
ResponseEntity < String > response = restTemplate . getForEntity (
apiUrl + "/health" , String . class
);
assertEquals ( HttpStatus . OK , response . getStatusCode ());
}
}
Best Practices
Container Management
Use static containers for test classes : Share containers across all test methods to reduce startup time and resource usage
Implement container reuse : Enable testcontainers.reuse.enable=true for faster local development test cycles
Clean up resources : Use @AfterAll or try-with-resources when manually managing containers outside JUnit integration
Use specific image tags : Avoid latest tag; use specific versions like postgres:15-alpine for reproducible tests
Parallel container startup : Use Startables.deepStart() to start multiple independent containers simultaneously
Minimize container restarts : Use class-level @Container instead of method-level when possible
Choose lightweight images : Prefer Alpine-based images (e.g., postgres:15-alpine) to reduce pull time and disk usage
Implement wait strategies wisely : Use appropriate wait strategies to avoid unnecessary delays while ensuring container readiness
Testing Strategy
Test against production-like dependencies : Use real database engines and message brokers instead of embedded versions
Isolate test data : Ensure each test creates and cleans up its own data to prevent test interdependencies
Use network aliases : Create custom networks and use meaningful aliases for inter-container communication
Implement health checks : Always configure proper wait strategies to ensure containers are fully ready before tests execute
CI/CD Integration
Verify Docker availability : Ensure CI environment has Docker installed and accessible
Configure timeouts appropriately : Set realistic startup timeouts considering CI environment performance
Use image caching : Configure CI to cache Docker images to speed up subsequent runs
Monitor resource usage : Be aware of memory and CPU limits in CI environments; adjust container configurations accordingly
Security and Maintenance
Keep TestContainers updated : Regularly update to latest versions for security patches and new features
Use official images : Prefer official Docker images from verified publishers
Avoid privileged mode : Only use .withPrivilegedMode() when absolutely necessary
Review exposed ports : Only expose ports that are actually needed for testing
Troubleshooting
Issue
Solution
Container fails to start: "Cannot connect to Docker daemon"
Ensure Docker is running: docker ps. On Linux, add user to docker group: sudo usermod -aG docker $USER
Tests timeout during container startup
Increase timeout: .withStartupTimeout(Duration.ofMinutes(5)) or check Docker resources (CPU/Memory)
Port binding conflicts: "Address already in use"
Use dynamic ports: container.getMappedPort() instead of fixed ports, or stop conflicting services
Image pull fails: "manifest unknown"
Verify image name and tag exist on Docker Hub. Use specific tags instead of latest
Container starts but tests fail to connect
Check wait strategy is appropriate: add .waitingFor(Wait.forListeningPort()) or .waitingFor(Wait.forHealthcheck())
Out of memory errors during tests
Reduce number of parallel containers, increase Docker memory limit in Docker Desktop settings, or use .withReuse(true)
"Ryuk container not found" warnings
Disable Ryuk if needed: set testcontainers.ryuk.disabled=true in properties (not recommended for production)
Tests work locally but fail in CI
Ensure CI has Docker installed, check timeout settings, verify network connectivity, review CI environment resource limits
Database connection refused
Wait for database to be ready: use .waitingFor(Wait.forListeningPort()) and verify JDBC URL with container.getJdbcUrl()
Container logs show errors but tests pass
Enable log following: container.followOutput(new Slf4jLogConsumer(log)) to debug container issues
Slow test execution
Use container reuse, share containers at class level, start containers in parallel with Startables.deepStart()
"No such file or directory" when mounting volumes
Use absolute paths or MountableFile.forClasspathResource() for classpath resources
Network communication between containers fails
Create custom network: Network.newNetwork() and attach containers with .withNetwork(network) and .withNetworkAliases()
TestContainers properties not being read
Ensure testcontainers.properties is in src/test/resources and properly formatted
Container cleanup not happening
Check Ryuk container is running: docker ps | grep ryuk. Ensure tests complete normally without hanging
Available Modules
Module
Maven Artifact
Description
PostgreSQL
testcontainers-postgresql
PostgreSQL database containers
MySQL
testcontainers-mysql
MySQL database containers
MongoDB
testcontainers-mongodb
MongoDB document database
Kafka
testcontainers-kafka
Apache Kafka message broker
Redis
testcontainers-redis
Redis in-memory data store
Elasticsearch
testcontainers-elasticsearch
Elasticsearch search engine
Cassandra
testcontainers-cassandra
Cassandra NoSQL database
RabbitMQ
testcontainers-rabbitmq
RabbitMQ message broker
Selenium
testcontainers-selenium
Browser automation containers
LocalStack
testcontainers-localstack
AWS services emulation
Nginx