@Testcontainers Annotation
The `@Testcontainers` annotation enables the Testcontainers JUnit 5 extension, which manages the lifecycle of containers declared with `@Container`. It is commonly used to start and stop disposable infrastructure such as databases during integration tests.
`@Testcontainers` is used on a JUnit 5 test class to activate Testcontainers' JUnit Jupiter integration. The extension discovers fields annotated with `@Container` and manages their lifecycle around the tests.
A container field is typically declared as either static or instance-level. A `static` container is generally shared across all tests in the class, while an instance container is managed for each test instance. The exact lifecycle therefore depends on both the field's annotations and JUnit's test-instance behavior.
The annotation itself does not describe which container to run. You create a container object such as `PostgreSQLContainer`, annotate that field with `@Container`, and put `@Testcontainers` on the test class so the extension manages it.
This approach is useful for integration tests that need real external services rather than mocks. Testcontainers handles starting and stopping the container, while the test can obtain connection information such as the mapped port from the container object.
Key points
- `@Testcontainers` activates Testcontainers' JUnit 5 integration.
- It works with fields annotated `@Container`.
- Static containers can be reused across tests in a test class; instance containers have per-test-instance lifecycle.
- The annotation is for JUnit 5; JUnit 4 uses a different integration mechanism.
- The container image and configuration are defined by the container object, not by `@Testcontainers` itself.
Interview questions
Why would you use Testcontainers instead of mocking a database?
Testcontainers allows the test to communicate with a real database implementation instead of a simulated object. This can expose problems involving SQL behavior, schema compatibility, transactions, and database-specific features that mocks may not reproduce. The tradeoff is additional startup time and the need for a container runtime. It is therefore commonly used for integration tests rather than every unit test.
What is the difference between `@Testcontainers` and `@Container`?
`@Testcontainers` activates the Testcontainers JUnit 5 extension on the test class. `@Container` identifies a particular container field that the extension should manage. You normally use them together when writing JUnit 5 integration tests with Testcontainers. The first controls extension activation, while the second identifies the managed resource.
What does the `@Testcontainers` annotation do?
`@Testcontainers` enables the Testcontainers JUnit 5 extension for a test class. The extension finds fields marked with `@Container` and manages their lifecycle. This lets tests use real services such as PostgreSQL without manually starting and stopping the containers. The container configuration remains on the container object itself.
How do static and instance `@Container` fields differ?
A static container is associated with the test class and can be reused by multiple test methods in that class. An instance container is associated with a test instance and can therefore have a shorter lifecycle. The choice affects startup cost and test isolation. JUnit's test-instance lifecycle also matters when reasoning about instance fields.