Generated banner for Java Testcontainers
Generated logo for Java Testcontainers

Java Testcontainers

GitHubOfficialFirst committed by jduboisDistributed by GitHub

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

Write reliable integration tests in plain Java with Testcontainers 2.x: JUnit Jupiter lifecycle, singleton containers, reuse, generic containers, wait strategies, networks, init scripts, Docker Compose, CI and Docker/Podman setup. Use when adding or fixing Testcontainers tests, or migrating from 1.x. Framework-neutral.
— the description by jdubois

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides guidance on implementing integration tests in Java using Testcontainers 2.x. It covers the setup of containerized dependencies like databases, message brokers, and caches, ensuring tests run against real infrastructure rather than mocks. The skill emphasizes framework-neutral practices, lifecycle management, wait strategies, and CI/CD integration, while highlighting key changes from the 1.x version.

What it does

  • Configures containerized dependencies for integration testing in Java.
  • Provides patterns for container lifecycle management including singleton and per-method setups.
  • Defines wait strategies to ensure services are ready before tests execute.
  • Supports multi-container networking and Docker Compose integration.
  • Offers troubleshooting steps for CI environments and Docker/Podman configurations.
  • Outlines migration paths and dependency management for Testcontainers 2.x.

When to use it

  • When you need to write integration tests that require real database, cache, or broker instances.
  • When migrating existing integration tests from Testcontainers 1.x to 2.x.
  • When you need to ensure test environments match production infrastructure.
  • When setting up CI pipelines that require reliable, containerized test dependencies.

Advantages

  • Runs tests against real production-like dependencies.
  • Framework-neutral implementation works with various Java testing setups.
  • Provides robust lifecycle control to balance test speed and isolation.
  • Reduces flakiness by using explicit wait strategies instead of arbitrary sleeps.

Usage examples

“How do I set up a PostgreSQL container for my JUnit 5 integration test?”
The agent provides a code snippet using the @Testcontainers and @Container annotations, showing how to define a static PostgreSQLContainer and retrieve the JDBC URL.
“My integration test is failing because the database isn't ready yet. How do I fix this?”
The agent explains how to implement wait strategies, such as Wait.forListeningPorts() or Wait.forLogMessage(), to ensure the container is fully initialized before the test proceeds.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/github/java-testcontainers/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip java-testcontainers.zip -d .agents/skills

Documentation by jdubois

Java Testcontainers (2.x)

Run real dependencies (databases, brokers, caches) in Docker for integration tests. This skill is framework-neutral. If the project uses Spring Boot and the spring-boot-testing skill is installed, use it for @ServiceConnection, @DynamicPropertySource and test slices; for Quarkus, rely on Dev Services (Quarkus skills/docs), not hand-wired containers.

Workflow

  1. Detect the existing version (pom.xml / build.gradle) and test framework (JUnit Jupiter). Testcontainers 2.x has no JUnit 4 support.

  2. Pick the smallest container that matches production (same DB engine and major version; never H2 as a stand-in for behavior you care about).

  3. Choose a lifecycle (table below), configure waiting, wire connection details into the code under test.

  4. Run locally and in CI; check Docker availability and speed.

Testcontainers 2.x essentials

  • Artifacts are all prefixed testcontainers-: org.testcontainers:testcontainers-junit-jupiter, testcontainers-postgresql, testcontainers-mysql, testcontainers-kafka, etc. (1.x: junit-jupiter, postgresql). Core stays org.testcontainers:testcontainers.

  • Module container classes moved to per-module packages, e.g. org.testcontainers.postgresql.PostgreSQLContainer (1.x: org.testcontainers.containers.PostgreSQLContainer). Core classes (GenericContainer, Network, wait.strategy.*) remain under org.testcontainers.containers.

  • Module container classes are no longer generic: PostgreSQLContainer, not PostgreSQLContainer<?>.

  • Use a BOM to keep versions aligned: org.testcontainers:testcontainers-bom:2.0.5 (verify the current release on Maven Central).

  • Docker Compose: use ComposeContainer (Compose v2); DockerComposeContainer is still present in 2.0.5 (older API); prefer ComposeContainer.

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>testcontainers-bom</artifactId>
      <version>2.0.5</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencies>
  <dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers-junit-jupiter</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers-postgresql</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.14</version>
    <scope>test</scope>
  </dependency>
</dependencies>

Gradle: testImplementation platform("org.testcontainers:testcontainers-bom:2.0.5"), then the same Testcontainers artifacts without versions, plus testRuntimeOnly "org.postgresql:postgresql:42.7.14". The Testcontainers module does not bundle the JDBC driver; skip the explicit driver when the project already depends on one (e.g. via Spring Boot's BOM).

Minimal test

import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.postgresql.PostgreSQLContainer;

@Testcontainers
class CustomerStoreIT {

    @Container
    static final PostgreSQLContainer POSTGRES = new PostgreSQLContainer("postgres:17-alpine");

    @Test
    void connects() throws Exception {
        try (var c = java.sql.DriverManager.getConnection(
                POSTGRES.getJdbcUrl(), POSTGRES.getUsername(), POSTGRES.getPassword())) {
            org.junit.jupiter.api.Assertions.assertTrue(c.isValid(2));
        }
    }
}

Always pin the image tag (never latest); match the production major version.

Lifecycle decision

NeedPattern
One container per test classstatic @Container field
Fresh container per test method (slow, strong isolation)non-static @Container field
One container for the whole test run (fastest)singleton holder, see references/lifecycle-and-reuse.md
Keep containers between local runswithReuse(true) + opt-in property, local only

Prefer sharing a container and isolating data (truncate/rollback, unique schema or DB per test) over restarting containers.

Checklist

  • [ ] Image tag pinned and matches production.

  • [ ] Wait strategy meaningful (module defaults are usually fine; custom for GenericContainer).

  • [ ] No fixed host ports; use getMappedPort/getHost.

  • [ ] Containers shared across classes where possible (singleton).

  • [ ] Integration tests named *IT and run by failsafe (Maven) or a separate Gradle test task, so unit tests stay fast.

  • [ ] No secrets or real credentials in test containers.

  • [ ] CI runner has Docker; log output is captured on failure.

References

  • references/lifecycle-and-reuse.md: per-class/per-method, singleton pattern, reuse, parallel runs, data isolation.

  • references/containers-and-waiting.md: modules vs GenericContainer, wait strategies, env/config, init scripts, copy files, networks, multi-container setups, Docker Compose.

  • references/environment-ci-troubleshooting.md: Docker/Podman/Colima setup, CI, private registries, performance, common errors, 1.x to 2.x migration table.

Official docs: https://java.testcontainers.org/

Upgrading to 2.x: no dedicated migration page was found on java.testcontainers.org; read the 2.0.0 release notes https://github.com/testcontainers/testcontainers-java/releases/tag/2.0.0 and all releases https://github.com/testcontainers/testcontainers-java/releases for the target version, and prefer them over this skill when they conflict.

Files

references/environment-ci-troubleshooting.md

Environment, CI, troubleshooting, migration

Docker availability

Testcontainers needs a Docker-API-compatible daemon. Check with docker info.

  • Docker Desktop, Rancher Desktop, Colima, OrbStack, and Podman (Docker-compatible socket) work. When the socket is non-standard, set DOCKER_HOST (e.g. unix:///run/user/1000/podman/podman.sock); with rootless Podman, TESTCONTAINERS_RYUK_DISABLED=true may be needed if the Ryuk sidecar cannot mount the socket (then clean up containers yourself).

  • Settings can live in ~/.testcontainers.properties (docker.host=...) or TESTCONTAINERS_* environment variables.

  • Colima on macOS: DOCKER_HOST=unix://$HOME/.colima/default/docker.sock and TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock.

  • Without Docker, tests fail with "Could not find a valid Docker environment". Fix the environment, or gate optional local runs with @Testcontainers(disabledWithoutDocker = true).

CI

  • GitHub Actions ubuntu-* runners ship Docker; no setup needed. Self-hosted runners must expose the socket to the job user.

  • Docker-in-Docker CI (GitLab, containerized Jenkins agents): mount the host socket or use a DinD service and set DOCKER_HOST; set TESTCONTAINERS_HOST_OVERRIDE if the daemon host is not localhost.

  • Cache images between runs and avoid Docker Hub rate limits with a registry mirror (hub.image.name.prefix in properties or TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX).

  • Private registries: docker login (credential helpers in ~/.docker/config.json are honored).

  • Do not enable container reuse in CI.

  • Print container logs on failure and keep timeouts generous (2 minutes for heavy images).

  • Separate unit and integration phases (maven-failsafe-plugin with *IT, or a Gradle integrationTest task).

Performance checklist

  1. Singleton containers across classes (see lifecycle-and-reuse.md).

  2. Small images (-alpine, slim) pinned by tag; pre-pull in CI.

  3. withTmpFs for database data dirs.

  4. Truncate/rollback instead of restarting.

  5. Start independent containers in parallel (Startables.deepStart(a, b, c).join(), org.testcontainers.lifecycle.Startables).

  6. Avoid heavyweight services if a lighter equivalent preserves the behavior under test.

Common errors

SymptomLikely cause / fix
Could not find a valid Docker environmentDaemon down or wrong socket; set DOCKER_HOST.
Container startup timeoutWrong wait strategy, image crash (read getLogs()), low resources; raise timeout.
Connection refused right after startPort open but app not ready; use HTTP/log/healthcheck wait.
Works for first class, fails for next@Container on a singleton stopped after first class; remove the annotation.
Container cannot reach anotherMapped port used inside a network; use alias + internal port.
ClassNotFoundException: ...containers.PostgreSQLContainer2.x package move, see below.
Ryuk errorsRootless/Podman socket mount; see Docker availability.
Surefire The exit has elapsed 30 seconds after System.exit(0) / going to kill self fork JVMA JVM shutdown hook hangs after the tests (not a Testcontainers-specific message). Not reproduced with Testcontainers 2.0.5 + Surefire 3.5.5/3.5.6 + Docker Desktop 29.8 on JDK 21/25/27, with static @Container, @ServiceConnection and a Spring-managed container bean (all exit in a second), so Docker Desktop, Ryuk and Testcontainers 2.x are not the cause by themselves. Diagnose: run jstack <fork pid> (or jcmd Thread.print) during the 30 s and read which hook thread is blocked (typically an application or Spring context hook closing a pool or client against a container that is already gone, or a user-registered hook); close such resources before the container stops, or set -Dsurefire.exitTimeout=<seconds> lower to fail fast.

1.x to 2.x migration

1.x2.x
org.testcontainers:junit-jupiterorg.testcontainers:testcontainers-junit-jupiter
org.testcontainers:postgresql (and other modules)org.testcontainers:testcontainers-postgresql (same prefix rule)
org.testcontainers.containers.PostgreSQLContainer<?>org.testcontainers.postgresql.PostgreSQLContainer (non-generic)
JUnit 4 @Rule/@ClassRuleRemoved; migrate tests to JUnit Jupiter
DockerComposeContainerComposeContainer (Compose v2)
Per-module versionstestcontainers-bom

Steps: import the BOM, rename artifacts, fix imports module by module (the compiler flags each moved class), remove <?> from module container types, convert JUnit 4 tests. Check the release notes for the modules you use; each module's package follows org.testcontainers.<module>.

Docs: https://java.testcontainers.org/; releases: https://github.com/testcontainers/testcontainers-java/releases

Requirements and compatibility

Written for: GitHub Copilot

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

First committed by
GitHub avatar of jduboisjdubois
Publisher
GitHub (Official)
Distributed by
GitHub
Source
github/awesome-copilot · skills/java-testcontainers · commit 797337f
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced
Contributors
jdubois

AutoGineer is not affiliated with or endorsed by jdubois or GitHub.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download java-testcontainers.zip