Java library for integration testing with Docker containers
Testcontainers provides specialized container modules for popular databases, message queues, and other services. These modules extend GenericContainer or JdbcDatabaseContainer with service-specific configuration methods and connection helpers, simplifying integration testing against real service instances.
Why Use Modules?
getJdbcUrl(), getConnectionString()When to Use Modules vs GenericContainer:
Modules are distributed as separate Maven/Gradle dependencies:
Maven:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId> <!-- Module name -->
<version>2.0.3</version>
<scope>test</scope>
</dependency>Gradle:
testImplementation 'org.testcontainers:postgresql:2.0.3'| Module | Artifact ID | Container Class | Connection Method |
|---|---|---|---|
| PostgreSQL | postgresql | PostgreSQLContainer | getJdbcUrl() |
| MySQL | mysql | MySQLContainer | getJdbcUrl() |
| MariaDB | mariadb | MariaDBContainer | getJdbcUrl() |
| MongoDB | mongodb | MongoDBContainer | getConnectionString() |
| Oracle XE | oracle-xe | OracleContainer | getJdbcUrl() |
| Oracle Free | oracle-free | OracleFreeContainer | getJdbcUrl() |
| MS SQL Server | mssqlserver | MSSQLServerContainer | getJdbcUrl() |
| DB2 | db2 | Db2Container | getJdbcUrl() |
| Cassandra | cassandra | CassandraContainer | getContactPoint() |
| Neo4j | neo4j | Neo4jContainer | getBoltUrl() |
| CockroachDB | cockroachdb | CockroachContainer | getJdbcUrl() |
| Couchbase | couchbase | CouchbaseContainer | getConnectionString() |
| ClickHouse | clickhouse | ClickHouseContainer | getJdbcUrl() |
| InfluxDB | influxdb | InfluxDBContainer | getUrl() |
| QuestDB | questdb | QuestDBContainer | getHttpUrl() |
| TiDB | tidb | TiDBContainer | getJdbcUrl() |
| YugabyteDB | yugabytedb | YugabyteDBContainer | getJdbcUrl() |
| CrateDB | cratedb | CrateDBContainer | getJdbcUrl() |
| OrientDB | orientdb | OrientDBContainer | getDbUrl() |
| Databend | databend | DatabendContainer | getJdbcUrl() |
| ScyllaDB | scylladb | ScyllaDBContainer | getContactPoint() |
| OceanBase | oceanbase | OceanBaseContainer | getJdbcUrl() |
| Module | Artifact ID | Container Class | Connection Method |
|---|---|---|---|
| Kafka | kafka | KafkaContainer | getBootstrapServers() |
| RabbitMQ | rabbitmq | RabbitMQContainer | getAmqpUrl() / getHttpUrl() |
| Pulsar | pulsar | PulsarContainer | getPulsarBrokerUrl() |
| Redpanda | redpanda | RedpandaContainer | getBootstrapServers() |
| ActiveMQ | activemq | ActiveMQContainer | getBrokerUrl() |
| HiveMQ | hivemq | HiveMQContainer | getMqttPort() |
| Solace | solace | SolaceContainer | getOrigin() |
| Module | Artifact ID | Container Class | Connection Method |
|---|---|---|---|
| Elasticsearch | elasticsearch | ElasticsearchContainer | getHttpHostAddress() |
| Solr | solr | SolrContainer | getSolrUrl() |
| Milvus | milvus | MilvusContainer | getEndpoint() |
| Qdrant | qdrant | QdrantContainer | getGrpcHostAddress() |
| Weaviate | weaviate | WeaviateContainer | getHttpHostAddress() |
| Pinecone | pinecone | PineconeContainer | getEndpoint() |
| ChromaDB | chromadb | ChromaDBContainer | getEndpoint() |
| Typesense | typesense | TypesenseContainer | getHost() |
| Module | Artifact ID | Container Class | Use Case |
|---|---|---|---|
| LocalStack | localstack | LocalStackContainer | AWS service emulation |
| Azure | azure | AzuriteContainer | Azure Blob/Queue/Table storage |
| GCloud | gcloud | FirestoreEmulatorContainer, PubSubEmulatorContainer, BigtableEmulatorContainer | Google Cloud emulation |
| Vault | vault | VaultContainer | HashiCorp Vault secrets management |
| Consul | consul | ConsulContainer | Service discovery |
| MinIO | minio | MinIOContainer | S3-compatible object storage |
| K3s | k3s | K3sContainer | Lightweight Kubernetes |
| K6 | k6 | K6Container | Load testing |
| Module | Artifact ID | Container Class | Use Case |
|---|---|---|---|
| Selenium | selenium | BrowserWebDriverContainer | Browser automation |
| MockServer | mockserver | MockServerContainer | HTTP API mocking |
| Nginx | nginx | NginxContainer | Web server / reverse proxy |
| Toxiproxy | toxiproxy | ToxiproxyContainer | Network failure simulation |
| OpenFGA | openfga | OpenFGAContainer | Authorization service |
| Grafana | grafana | GrafanaContainer | Metrics visualization |
| LDAP | ldap | LdapContainer | LDAP server |
| Ollama | ollama | OllamaContainer | LLM inference |
| Presto | presto | PrestoContainer | Distributed SQL query |
| Trino | trino | TrinoContainer | Distributed SQL query |
| Timeplus | timeplus | TimeplusContainer | Stream processing |
PostgreSQL database container with JDBC support.
package org.testcontainers.postgresql;
/**
* PostgreSQL database container.
* Extends JdbcDatabaseContainer with PostgreSQL-specific configuration.
*
* Default port: 5432
* Default database: test
* Default username: test
* Default password: test
* JDBC driver: org.postgresql.Driver
*/
public class PostgreSQLContainer<SELF extends PostgreSQLContainer<SELF>>
extends JdbcDatabaseContainer<SELF> {
/**
* Create PostgreSQL container with default postgres:latest image.
* @deprecated Use constructor with DockerImageName
*/
@Deprecated
public PostgreSQLContainer();
/**
* Create PostgreSQL container with specific image.
*
* @param dockerImageName PostgreSQL Docker image
*/
public PostgreSQLContainer(DockerImageName dockerImageName);
/**
* Create PostgreSQL container with image name string.
*
* @param dockerImageName image name (e.g., "postgres:15")
*/
public PostgreSQLContainer(String dockerImageName);
/**
* Get JDBC URL for connecting to the database.
* Format: jdbc:postgresql://host:port/database
*
* @return JDBC URL string
*/
@Override
public String getJdbcUrl();
/**
* Get JDBC driver class name.
*
* @return "org.postgresql.Driver"
*/
@Override
public String getDriverClassName();
/**
* Get the database name.
*
* @return database name (default: "test")
*/
@Override
public String getDatabaseName();
/**
* Get the username.
*
* @return username (default: "test")
*/
@Override
public String getUsername();
/**
* Get the password.
*
* @return password (default: "test")
*/
@Override
public String getPassword();
/**
* Get the test query SQL used for connection validation.
*
* @return test query (default: "SELECT 1")
*/
@Override
protected String getTestQueryString();
/**
* Set database name.
*
* @param databaseName database name
* @return this container
*/
public SELF withDatabaseName(String databaseName);
/**
* Set username.
*
* @param username username
* @return this container
*/
public SELF withUsername(String username);
/**
* Set password.
*
* @param password password
* @return this container
*/
public SELF withPassword(String password);
/**
* Set initialization script to run on startup.
* Script is executed after the database is ready.
*
* @param initScriptPath classpath resource path to SQL script
* @return this container
*/
public SELF withInitScript(String initScriptPath);
}Usage Example:
import org.testcontainers.postgresql.PostgreSQLContainer;
import org.testcontainers.utility.DockerImageName;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
// Basic usage
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");
postgres.start();
// Get connection details
String jdbcUrl = postgres.getJdbcUrl();
String username = postgres.getUsername();
String password = postgres.getPassword();
// Connect using JDBC
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
ResultSet rs = conn.createStatement().executeQuery("SELECT version()");
rs.next();
System.out.println("PostgreSQL version: " + rs.getString(1));
}
// Custom configuration
PostgreSQLContainer<?> customPostgres = new PostgreSQLContainer<>(
DockerImageName.parse("postgres:15-alpine"))
.withDatabaseName("mydb")
.withUsername("myuser")
.withPassword("mypass")
.withInitScript("schema.sql"); // Run initialization script
customPostgres.start();MySQL database container with JDBC support.
package org.testcontainers.mysql;
/**
* MySQL database container.
* Extends JdbcDatabaseContainer with MySQL-specific configuration.
*
* Default port: 3306
* Default database: test
* Default username: test
* Default password: test
* JDBC driver: com.mysql.cj.jdbc.Driver (or com.mysql.jdbc.Driver for older versions)
*
* Automatically adds useSSL=false and allowPublicKeyRetrieval=true to JDBC URL.
*/
public class MySQLContainer<SELF extends MySQLContainer<SELF>>
extends JdbcDatabaseContainer<SELF> {
/**
* Create MySQL container with specific image.
*
* @param dockerImageName MySQL Docker image
*/
public MySQLContainer(DockerImageName dockerImageName);
/**
* Create MySQL container with image name string.
*
* @param dockerImageName image name (e.g., "mysql:8.0")
*/
public MySQLContainer(String dockerImageName);
/**
* Get JDBC URL for connecting to the database.
* Format: jdbc:mysql://host:port/database?useSSL=false&allowPublicKeyRetrieval=true
*
* @return JDBC URL string
*/
@Override
public String getJdbcUrl();
/**
* Get JDBC driver class name.
*
* @return "com.mysql.cj.jdbc.Driver" or fallback for older versions
*/
@Override
public String getDriverClassName();
/**
* Get the database name.
*
* @return database name (default: "test")
*/
@Override
public String getDatabaseName();
/**
* Get the username.
*
* @return username (default: "test")
*/
@Override
public String getUsername();
/**
* Get the password.
*
* @return password (default: "test")
*/
@Override
public String getPassword();
/**
* Get the test query SQL.
*
* @return test query (default: "SELECT 1")
*/
@Override
protected String getTestQueryString();
/**
* Set database name.
*
* @param databaseName database name
* @return this container
*/
public SELF withDatabaseName(String databaseName);
/**
* Set username.
*
* @param username username
* @return this container
*/
public SELF withUsername(String username);
/**
* Set password.
*
* @param password password
* @return this container
*/
public SELF withPassword(String password);
/**
* Set MySQL configuration file override.
* Mounts a custom my.cnf file to override MySQL configuration.
*
* @param configurationPath classpath path to my.cnf file
* @return this container
*/
public SELF withConfigurationOverride(String configurationPath);
/**
* Set initialization script.
*
* @param initScriptPath classpath resource path to SQL script
* @return this container
*/
public SELF withInitScript(String initScriptPath);
}Usage Example:
import org.testcontainers.mysql.MySQLContainer;
// Basic usage
MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0");
mysql.start();
String jdbcUrl = mysql.getJdbcUrl();
// jdbc:mysql://localhost:32768/test?useSSL=false&allowPublicKeyRetrieval=true
// Custom configuration with my.cnf override
MySQLContainer<?> customMySQL = new MySQLContainer<>("mysql:8.0")
.withDatabaseName("appdb")
.withUsername("app")
.withPassword("secret")
.withConfigurationOverride("mysql-config") // Mounts classpath:mysql-config/my.cnf
.withInitScript("init.sql");
customMySQL.start();
// Connect
try (Connection conn = DriverManager.getConnection(
customMySQL.getJdbcUrl(),
customMySQL.getUsername(),
customMySQL.getPassword())) {
// Use connection
}MongoDB NoSQL database container (does NOT extend JdbcDatabaseContainer).
package org.testcontainers.mongodb;
/**
* MongoDB database container.
* Extends GenericContainer (not JdbcDatabaseContainer).
*
* Default port: 27017
* No default authentication
* Uses MongoDB connection strings (not JDBC URLs)
*
* Supports:
* - Standalone mode (default)
* - Replica set mode (required for transactions)
* - Sharding mode
*/
public class MongoDBContainer extends GenericContainer<MongoDBContainer> {
/**
* Create MongoDB container with specific image.
*
* @param dockerImageName MongoDB Docker image
*/
public MongoDBContainer(DockerImageName dockerImageName);
/**
* Create MongoDB container with image name string.
*
* @param dockerImageName image name (e.g., "mongo:7.0")
*/
public MongoDBContainer(String dockerImageName);
/**
* Get MongoDB connection string.
* Format: mongodb://host:port
*
* @return MongoDB connection string
*/
public String getConnectionString();
/**
* Get replica set connection URL.
* Only valid if withReplicaSet() was called.
* Format: mongodb://host:port/?replicaSet=rs0
*
* @return replica set URL
*/
public String getReplicaSetUrl();
/**
* Get replica set connection URL for a specific database.
* Format: mongodb://host:port/database?replicaSet=rs0
*
* @param database database name
* @return replica set URL with database
*/
public String getReplicaSetUrl(String database);
/**
* Enable replica set mode.
* Required for MongoDB transactions.
* Configures single-node replica set named "rs0".
*
* @return this container
*/
public MongoDBContainer withReplicaSet();
/**
* Enable sharding mode.
* Configures MongoDB with sharding support.
*
* @return this container
*/
public MongoDBContainer withSharding();
}Usage Example:
import org.testcontainers.mongodb.MongoDBContainer;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
// Basic standalone MongoDB
MongoDBContainer mongodb = new MongoDBContainer("mongo:7.0");
mongodb.start();
String connectionString = mongodb.getConnectionString();
// mongodb://localhost:32769
// Connect using MongoDB driver
try (MongoClient mongoClient = MongoClients.create(connectionString)) {
MongoDatabase database = mongoClient.getDatabase("testdb");
// Use database
}
// Replica set mode (required for transactions)
MongoDBContainer replicaSet = new MongoDBContainer("mongo:7.0")
.withReplicaSet();
replicaSet.start();
String replicaSetUrl = replicaSet.getReplicaSetUrl("mydb");
// mongodb://localhost:32770/mydb?replicaSet=rs0
try (MongoClient client = MongoClients.create(replicaSetUrl)) {
// Can now use transactions
ClientSession session = client.startSession();
session.startTransaction();
try {
// Transactional operations
session.commitTransaction();
} catch (Exception e) {
session.abortTransaction();
}
}Apache Kafka message broker container.
package org.testcontainers.kafka;
/**
* Kafka message broker container.
* Runs Kafka with embedded ZooKeeper or KRaft mode.
*
* Default port: 9093 (internal), mapped dynamically
* Supports both ZooKeeper and KRaft (ZooKeeper-less) modes
*/
public class KafkaContainer extends GenericContainer<KafkaContainer> {
/**
* Create Kafka container with specific image.
*
* @param dockerImageName Kafka Docker image (confluentinc/cp-kafka)
*/
public KafkaContainer(DockerImageName dockerImageName);
/**
* Get Kafka bootstrap servers connection string.
* Format: PLAINTEXT://host:port
*
* @return bootstrap servers string
*/
public String getBootstrapServers();
/**
* Enable KRaft mode (ZooKeeper-less).
* Available in Kafka 3.3+.
*
* @return this container
*/
public KafkaContainer withKraft();
/**
* Create topics on startup.
* Topics are automatically created after Kafka is ready.
*
* @param numPartitions number of partitions per topic
* @param replicationFactor replication factor (use 1 for single broker)
* @param topics topic names to create
* @return this container
*/
public KafkaContainer withCreateTopics(int numPartitions, short replicationFactor, String... topics);
}Usage Example:
import org.testcontainers.kafka.KafkaContainer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Properties;
// Basic Kafka
KafkaContainer kafka = new KafkaContainer(
DockerImageName.parse("confluentinc/cp-kafka:7.5.0"));
kafka.start();
String bootstrapServers = kafka.getBootstrapServers();
// PLAINTEXT://localhost:32771
// Producer configuration
Properties producerProps = new Properties();
producerProps.put("bootstrap.servers", bootstrapServers);
producerProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
producerProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer<String, String> producer = new KafkaProducer<>(producerProps);
producer.send(new ProducerRecord<>("test-topic", "key", "value"));
// With pre-created topics
KafkaContainer kafkaWithTopics = new KafkaContainer(
DockerImageName.parse("confluentinc/cp-kafka:7.5.0"))
.withCreateTopics(3, (short) 1, "events", "commands", "queries");
kafkaWithTopics.start();All JDBC database modules (PostgreSQLContainer, MySQLContainer, etc.) share this pattern:
// Common JDBC database methods
JdbcDatabaseContainer<?> db = new PostgreSQLContainer<>("postgres:15");
db.start();
// Connection details
String jdbcUrl = db.getJdbcUrl(); // JDBC URL
String username = db.getUsername(); // Username (default: "test")
String password = db.getPassword(); // Password (default: "test")
String databaseName = db.getDatabaseName(); // Database name (default: "test")
String driverClassName = db.getDriverClassName(); // JDBC driver class
// JDBC connection
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
// Use connection
}
// Common configuration
db.withDatabaseName("mydb")
.withUsername("user")
.withPassword("pass")
.withInitScript("init.sql"); // Run SQL script on startupNoSQL databases use service-specific connection methods:
// MongoDB
MongoDBContainer mongo = new MongoDBContainer("mongo:7.0");
mongo.start();
String connectionString = mongo.getConnectionString();
MongoClient client = MongoClients.create(connectionString);
// Cassandra
CassandraContainer cassandra = new CassandraContainer("cassandra:4.1");
cassandra.start();
InetSocketAddress contactPoint = cassandra.getContactPoint();
CqlSession session = CqlSession.builder()
.addContactPoint(contactPoint)
.withLocalDatacenter(cassandra.getLocalDatacenter())
.build();✅ Module exists for your service ✅ You need JDBC URL / connection string helpers ✅ You want service-specific configuration (replica sets, sharding, etc.) ✅ You need initialization scripts or pre-configuration
Example:
// ✅ Good - use PostgreSQL module
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
.withInitScript("schema.sql");
String jdbcUrl = postgres.getJdbcUrl(); // Easy!✅ No specialized module exists for your service ✅ You're using a custom or modified image ✅ You need maximum flexibility ✅ Service doesn't need special configuration
Example:
// ✅ Good - Redis has no specialized module
GenericContainer<?> redis = new GenericContainer<>("redis:7.0")
.withExposedPorts(6379);
redis.start();
// Manual connection details
String host = redis.getHost();
int port = redis.getMappedPort(6379);Testcontainers modules do NOT include JDBC drivers. You must add them separately:
PostgreSQL:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
<scope>test</scope>
</dependency>MySQL:
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.1.0</version>
<scope>test</scope>
</dependency>MongoDB:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>import org.testcontainers.postgresql.PostgreSQLContainer;
import org.testcontainers.mysql.MySQLContainer;
import org.testcontainers.mongodb.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
@Testcontainers
class MultiDatabaseTest {
@Container
private static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("user")
.withPassword("pass");
@Container
private static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0")
.withDatabaseName("testdb");
@Container
private static MongoDBContainer mongodb = new MongoDBContainer("mongo:7.0");
@Test
void testPostgreSQL() throws Exception {
try (Connection conn = DriverManager.getConnection(
postgres.getJdbcUrl(),
postgres.getUsername(),
postgres.getPassword())) {
conn.createStatement().execute("CREATE TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(255))");
conn.createStatement().execute("INSERT INTO users (name) VALUES ('Alice')");
var rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM users");
rs.next();
assertEquals(1, rs.getInt(1));
}
}
@Test
void testMySQL() throws Exception {
try (Connection conn = DriverManager.getConnection(
mysql.getJdbcUrl(),
mysql.getUsername(),
mysql.getPassword())) {
conn.createStatement().execute("CREATE TABLE products (id INT PRIMARY KEY, name VARCHAR(255))");
conn.createStatement().execute("INSERT INTO products VALUES (1, 'Widget')");
var rs = conn.createStatement().executeQuery("SELECT * FROM products WHERE id = 1");
rs.next();
assertEquals("Widget", rs.getString("name"));
}
}
@Test
void testMongoDB() {
try (MongoClient client = MongoClients.create(mongodb.getConnectionString())) {
var database = client.getDatabase("testdb");
var collection = database.getCollection("items");
collection.insertOne(new Document("name", "Item1"));
assertEquals(1, collection.countDocuments());
}
}
}This modules overview provides coding agents with practical guidance for choosing and using Testcontainers specialized modules, with complete API documentation for the most common database and message queue containers.
Install with Tessl CLI
npx tessl i tessl/maven-org-testcontainers--testcontainersdocs