Testcontainers for Java
repository·main·Indexed 11 days ago
https://github.com/testcontainers/testcontainers-javaA Java library that enables developers to run lightweight, throwaway instances of common databases, Selenium web browsers, or any other Docker-compatible software during JUnit tests to ensure a consistent, isolated environment for integration testing.
What's inside Testcontainers
- Testcontainers is a Java library designed to support JUnit tests by providing lightweight, throwaway instances of common dependencies. It allows you to run databases, Selenium web browsers, or any other software that can be packaged in a Docker container directly from your tests. This ensures a consistent, isolated environment for integration testing.
Use Testcontainers for database testing instead of H2 or local databases
mainTestcontainers provides database support for DAO unit tests and end-to-end integration tests. Use it in the following scenarios:
- Replacing H2 for feature-dependent tests: When your DAO tests require specific database features that H2 does not emulate, Testcontainers provides 100% compatibility by running the actual database inside a container.
- Replacing local or VM-based databases: When tests require a database to be present, Testcontainers ensures the database starts in a known, clean state, preventing contamination between test runs or differences between developer environments.
Note that while Testcontainers offers higher fidelity than H2, it is less performant. It is recommended to use mocks for higher-level components and limit the number of tests that interact directly with the database.
Use Testcontainers with external frameworks
mainTestcontainers provides direct integrations with several open-source testing frameworks. Instead of manually managing container lifecycles within your test code, you can use these specialized extensions to integrate container management directly into the framework's lifecycle (e.g., as part of property-based testing or specialized test runners).
Supported integrations include:
- jqwik: Use
jqwik-testcontainersfor property-based testing integration. - Kotest: Use
kotest-extensions-testcontainersfor Kotest-specific extensions. - Synthesized: Use
TDK-Testcontainersintegration for Synthesized data workflows. - TCI: Use the
Testcontainers Infrastructure (TCI) Frameworkfor infrastructure-level integration.
- jqwik: Use
Use Alternator with ScyllaDB
mainScyllaDB supports Alternator, which provides a DynamoDB-compatible API. You can enable Alternator in the ScyllaDB container and then use aDynamoDbClientto interact with it, making it suitable for testing applications designed for Amazon DynamoDB.Configure ScyllaDB CqlSession
mainWhen connecting to ScyllaDB via a
CqlSession, you can use different connection strategies provided by the container instance:- CQL Port: Use the standard CQL port mapped by the container.
- SSL: Configure the session to use SSL/TLS.
- Shard Awareness: Use the Shard Awareness port for optimized connectivity.
How the Testcontainers JUnit 5 extension works
mainThe JUnit 5 integration uses the
@Testcontainersannotation on a test class to enable the extension. The extension scans for fields annotated with@Containerand manages their lifecycle automatically by calling theirStartableinterface methods.Container Lifecycles
- Restarted Containers: If a container is declared as an instance field, it will be started before every test method and stopped after every test method.
- Shared Containers: If a container is declared as a static field, it will be shared between all test methods in the class. It starts once before the first test method and stops after the last test method has executed.
Important Limitations
- Parallel Execution: This extension is only tested with sequential test execution. Using it with parallel test execution is unsupported and may cause unintended side effects.
- Nested Classes: Shared containers (static fields) cannot be declared inside
@Nestedtest classes because nested classes must be non-static and cannot contain static fields.
@Testcontainers class MyTest { @Container static GenericContainer<?> sharedContainer = new GenericContainer<>("redis:latest"); // Shared across all methods @Container GenericContainer<?> restartedContainer = new GenericContainer<>("postgres:latest"); // Restarted for every method @Test void testOne() { // ... } }Use singleton containers with JUnit 4
mainThe singleton container pattern is an alternative to@Ruleor@ClassRulein JUnit 4. This pattern is typically used to share a single container instance across multiple test classes to improve performance by reducing the overhead of starting and stopping containers.Create images on-the-fly using ImageFromDockerfile
mainWhen no pre-existing Docker image is available, or when you need to customize a base image for specific tests, you can use
ImageFromDockerfileto build a temporary image from a Dockerfile.To use it, pass an instance of
ImageFromDockerfileas a constructor parameter toGenericContainer. Testcontainers will execute adocker buildto create the image before starting the container.GenericContainer container = new GenericContainer( new ImageFromDockerfile() // configuration here );Understand MySQL root user password behavior
mainThe MySQL module handles the
rootuser password as follows:- If no custom password is specified, the
rootuser defaults to the passwordtest. - If you specify a custom password for a database user, that password is automatically applied to the MySQL
rootuser as well.
- If no custom password is specified, the
ComposeContainer vs DockerComposeContainer
mainWhen choosing an API for Docker Compose support:
ComposeContainer: Supports Compose V2. This is the recommended approach.DockerComposeContainer: Utilizes Compose V1, which is deprecated by Docker.
The APIs are similar, and most usage patterns apply to both.
Decide if a new module is necessary
mainBefore creating a new module, evaluate if it provides enough value to be maintained as a first-class Testcontainers module. A new module is appropriate if it meets these criteria:
- Popularity: It enables use of a popular or rapidly growing technology.
- Value Add: It goes beyond a simple
GenericContainersnippet by:- Encapsulating complex container startup problems.
- Providing technology-specific wait strategies.
- Enabling straightforward usage of specific client libraries.
If the contribution does not meet these, consider publishing a code snippet, contributing an example to the repository, or publishing your own third-party library instead.
Understand Testcontainers Shaded Dependencies
mainTo prevent classpath conflicts with your application or test code, Testcontainers 'shades' (relocates) certain implementation-detail dependencies.
- Public API Dependencies: Libraries like
JUnit,docker-java-{api,transport},JNA, andvisible-assertionsare part of the public API and are NOT shaded. - Shaded Dependencies: Implementation details such as
docker-java-core,Guava, andOkHttpare shaded and relocated under theorg.testcontainers.shadedpackage to avoid version conflicts.
- Public API Dependencies: Libraries like