Appearance
Lesson 02 · Docker & Testcontainers
Beyond the 1Z0-830 exam
Integration tests need real dependencies — a database, a message broker, a downstream service. Docker packages those as reproducible containers; Testcontainers starts and stops them from your test code, so each run gets a clean, real dependency and tears it down afterward. This is the production-grade version of Module 16's "test databases."
Objectives
After this lesson you will be able to:
- Explain Docker images/containers at the level a tester needs.
- Use Testcontainers to run a real dependency in a test.
- Explain why this beats both mocks and a shared test server.
- Understand why these tests need Docker (and so are excluded from the default run).
Docker in one paragraph
A Docker image is an immutable, layered package of an app and everything it needs; a container is a running instance of an image. Because the image pins the OS, runtime, and config, a postgres:16 container behaves the same on your laptop and on the CI runner — reproducibility by construction. You pull images from a registry (Docker Hub) and run them with the Docker engine.
Testcontainers — real dependencies from a test
Rather than running docker run by hand, Testcontainers is a Java library that manages containers within the test lifecycle:
java
@Testcontainers
class OrderRepositoryIT {
@Container
static PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres:16");
@Test
void persistsAgainstRealPostgres() throws Exception {
try (Connection conn = DriverManager.getConnection(
db.getJdbcUrl(), db.getUsername(), db.getPassword())) {
// ... run the real schema + queries against an actual Postgres ...
}
}
}@Container+@Testcontainersstart the container before tests and stop it after.getJdbcUrl()exposes a random mapped port, so parallel runs don't collide.- The container is thrown away at the end — no leftover state, no shared fixture drift.
There are ready-made modules for Postgres, MySQL, Kafka, Redis, Elasticsearch, and a generic container for anything with an image.
Why it beats the alternatives
| Approach | Fidelity | Isolation | Cost |
|---|---|---|---|
| Mock/in-memory (H2) | low — not the real engine | high | cheap, fast |
| Testcontainers | high — the real engine | high — fresh per run | needs Docker, slower |
| Shared test server | high | low — shared state, contention | brittle, hard to reset |
Testcontainers hits the sweet spot for integration tests: the real engine (catching dialect/behavior differences H2 misses) with per-run isolation (unlike a shared server).
Trap — these tests need a Docker daemon
Testcontainers can't run without Docker. That's exactly why this course's infra-heavy labs are excluded from the default mvn test (Part B lab policy) and run only where Docker is available (your machine, or a CI runner with Docker). Don't put a Testcontainers test in the always-green default suite.
Gotcha — reuse images, don't pull every test
Pin image tags (postgres:16, not latest) for reproducibility, and let Testcontainers reuse the pulled image and (optionally) a shared container across a class. Starting a fresh container per test method is slow; per class or per suite is usually the right granularity.
SDET note
This is where Module 16 (test databases) and Module 20 meet. In CI you'd run H2-backed unit tests in the fast PR build, and Testcontainers-backed integration tests (tagged slow/integration) in the nightly full build (next lesson). The lab's TestSelector models exactly that split.
Key Takeaways
- A Docker image is a reproducible package; a container is a running instance — same behavior everywhere.
- Testcontainers starts/stops real dependencies (Postgres, Kafka, …) within the test lifecycle, on random ports, torn down afterward.
- It beats mocks (real engine) and shared servers (per-run isolation) for integration tests.
- These tests require Docker, so they're excluded from the always-green default run.
- Pin image tags and reuse containers per class/suite, not per method.
Lesson Quiz
A Docker image vs a container:
What does Testcontainers do?
Why does Testcontainers expose a random mapped port?
Compared with in-memory H2, Testcontainers offers…
Why are Testcontainers tests excluded from this course's default mvn test?
Next: Reports, Artifacts & Test Selection. This module's lab is in labs/src/main/java/com/jse21/m20_cicd/.