mirror of
https://github.com/docker/docs.git
synced 2026-03-27 14:28:47 +07:00
## Description Migrate 17 Testcontainers guides from testcontainers.com into the Docker docs site, covering Java (14 guides), .NET (2 guides), and Node.js (1 guide). This follows up on PR #24450 which added the initial Go and Python guides. Each guide is converted from AsciiDoc to Hugo Markdown, split into multi-chapter stepper navigation, updated to the latest Testcontainers API, and verified with passing tests running in containers. Java guides use testcontainers-java 2.0.4 with the new 2.x Maven coordinates and package names (e.g., `testcontainers-postgresql`, `org.testcontainers.postgresql.PostgreSQLContainer`). The Quarkus guide uses Quarkus 3.22.3 with TC 1.x managed by the Quarkus BOM, since no released Quarkus version ships TC 2.x yet. ## How to test All code snippets have been verified by running each guide's source repository tests inside Docker containers with the Docker socket mounted. To re-run the verification, use the `/testcontainers-guides-migrator` skill included in this PR (`.claude/skills/testcontainers-guides-migrator/SKILL.md`). The skill's Step 6 documents the exact container commands and macOS Docker Desktop workarounds (host override, docker-java API version, etc.) needed to run each language's tests: ``` /testcontainers-guides-migrator I want you to verify all the guides in this branch. Do a full review, verifying that all code snippets compile, the code is executable, and ALL the tests pass. Run them as docker containers, never locally. ``` ## Related issues or tickets Supersedes #24450 (expanded from 2 guides to all 19) ## Reviews - [ ] Technical review - [ ] Editorial review - [ ] Product review --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
114 lines
3.7 KiB
Markdown
114 lines
3.7 KiB
Markdown
---
|
|
title: Singleton containers pattern
|
|
linkTitle: Singleton containers
|
|
description: Share containers across multiple test classes using the singleton containers pattern.
|
|
weight: 40
|
|
---
|
|
|
|
As the number of test classes grows, starting containers for each class adds
|
|
up. The singleton containers pattern starts all required containers once in a
|
|
common base class and reuses them across all integration tests.
|
|
|
|
## Define the base class
|
|
|
|
Create an abstract base class that starts the containers in a static
|
|
initializer:
|
|
|
|
```java
|
|
package com.testcontainers.demo;
|
|
|
|
import org.testcontainers.postgresql.PostgreSQLContainer;
|
|
import org.testcontainers.kafka.ConfluentKafkaContainer;
|
|
|
|
public abstract class AbstractIntegrationTest {
|
|
|
|
static PostgreSQLContainer postgres = new PostgreSQLContainer(
|
|
"postgres:16-alpine");
|
|
static ConfluentKafkaContainer kafka = new ConfluentKafkaContainer(
|
|
"confluentinc/cp-kafka:7.8.0");
|
|
|
|
static {
|
|
postgres.start();
|
|
kafka.start();
|
|
}
|
|
}
|
|
```
|
|
|
|
The containers start once when the class loads and Testcontainers uses the
|
|
[Ryuk container](https://github.com/testcontainers/moby-ryuk) to remove them
|
|
after the JVM exits.
|
|
|
|
> [!TIP]
|
|
> Instead of starting containers sequentially, start them in parallel using
|
|
> `Startables.deepStart(postgres, kafka).join();`
|
|
|
|
## Extend the base class
|
|
|
|
Each test class inherits from the base class and reuses the same containers:
|
|
|
|
```java
|
|
class ProductControllerTest extends AbstractIntegrationTest {
|
|
|
|
ProductRepository productRepository;
|
|
|
|
@BeforeEach
|
|
void setUp() {
|
|
productRepository = new ProductRepository(...);
|
|
productRepository.deleteAll();
|
|
}
|
|
|
|
@Test
|
|
void shouldGetAllProducts() {
|
|
// test logic using the shared postgres container
|
|
}
|
|
}
|
|
```
|
|
|
|
## Avoid a common misconfiguration
|
|
|
|
A common mistake is combining singleton containers with the `@Testcontainers`
|
|
and `@Container` annotations:
|
|
|
|
```java
|
|
// DON'T DO THIS — containers will stop after each test class
|
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
@Testcontainers
|
|
public abstract class AbstractIntegrationTest {
|
|
|
|
@Container
|
|
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(
|
|
DockerImageName.parse("postgres:16-alpine"));
|
|
|
|
@DynamicPropertySource
|
|
static void configureProperties(DynamicPropertyRegistry registry) {
|
|
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
registry.add("spring.datasource.username", postgres::getUsername);
|
|
registry.add("spring.datasource.password", postgres::getPassword);
|
|
}
|
|
}
|
|
```
|
|
|
|
The `@Testcontainers` extension stops containers at the end of **each test
|
|
class**. Subsequent test classes reuse the cached Spring context, but the
|
|
containers are already stopped — causing connection failures.
|
|
|
|
Instead, use a static initializer or `@BeforeAll` to start the containers,
|
|
without the `@Testcontainers` and `@Container` annotations.
|
|
|
|
## Summary
|
|
|
|
- Use **JUnit 5 lifecycle callbacks** (`@BeforeAll`/`@AfterAll`) for
|
|
explicit control over container startup and shutdown.
|
|
- Use **extension annotations** (`@Testcontainers`/`@Container`) for less
|
|
boilerplate in single test classes.
|
|
- Use the **singleton containers pattern** (static initializer in a base class)
|
|
to share containers across multiple test classes.
|
|
- Don't mix singleton containers with `@Testcontainers`/`@Container`
|
|
annotations.
|
|
|
|
## Further reading
|
|
|
|
- [Testcontainers JUnit 5 quickstart](https://java.testcontainers.org/quickstart/junit_5_quickstart/)
|
|
- [Testcontainers singleton containers pattern](https://java.testcontainers.org/test_framework_integration/manual_lifecycle_control/#singleton-containers)
|
|
- [Testing a Spring Boot REST API with Testcontainers](/guides/testcontainers-java-spring-boot-rest-api/)
|