Skip to content
SDETRole
SDETRole

Glossary · CI/CD and DevOps

Testcontainers

Also called: Testcontainers for Java, testcontainers-node

Definition

A library that starts real dependencies such as databases, brokers or browsers in throwaway Docker containers from your test code, then removes them.

Testcontainers is an open-source library, available for Java, Node.js, .NET, Go, Python and other languages, that controls Docker from inside your tests. A test asks for “a Postgres 16 database”, the library starts a container, waits until it is ready, gives you the connection details, and removes the container when the test finishes. You test against the real database engine instead of an in-memory substitute or a shared environment.

Example (Testcontainers for Java 1.x, JUnit 5)

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

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;

import static org.junit.jupiter.api.Assertions.assertTrue;

@Testcontainers
class DatabaseIT {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");

    @Test
    void canQueryTheDatabase() throws Exception {
        try (Connection conn = DriverManager.getConnection(
                postgres.getJdbcUrl(), postgres.getUsername(), postgres.getPassword());
             ResultSet rs = conn.createStatement().executeQuery("SELECT 1")) {
            assertTrue(rs.next());
        }
    }
}

A static field shares one container across all tests in the class; an instance field would start a fresh one per test. In a real suite you would point your repository or Spring context at getJdbcUrl() and run migrations first.

Why it matters

Integration tests against H2 or SQLite often pass while the production database rejects the same SQL, because dialects, constraints and transaction behaviour differ. Testcontainers gives you the real engine with almost the convenience of a mock, and each run starts from a clean state, which removes shared-data flakiness.

Things to know

  • It needs a Docker-compatible runtime on the machine and on CI runners. GitHub-hosted Ubuntu runners have Docker available.
  • Container start-up costs seconds. Share containers per class or per suite, and reset data between tests rather than restarting the container.
  • Pin image versions to match production.
  • Ready-made modules exist for common services (Postgres, MySQL, Kafka, LocalStack, Selenium, and more), and GenericContainer covers any other image.
  • It complements test doubles rather than replacing them: unit tests should still stay in memory and fast.

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →