关于 docker-testcontainers
面向自动化集成测试的 Testcontainers 指导技能,展示如何在测试中运行数据库和中间件容器,并涵盖容器生命周期与 CI 配置。
主要功能
- 01提供 Java 和 Python 示例
- 02涵盖 PostgreSQL、Redis 和 Kafka 容器
- 03说明共享与按测试创建容器
- 04介绍 CI/CD 配置
- 05讲解端口映射与资源清理
适用场景
- 01为 Java 或 Python 集成测试启动数据库
- 02测试依赖 Redis 或 Kafka 的应用
- 03在 Spring Boot 测试中注入容器配置
- 04在 CI 流程中运行容器化测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ full-stack-skills/ docker-skills --skill docker-testcontainers安装后在 Claude Code 中输入/docker-testcontainers确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlexamples/01-java-postgres.md02-spring-boot-multi.mdreferences/01-container-lifecycle.md02-patterns-best-practices.md详细介绍
Docker Testcontainers — 集成测试容器
使用 Testcontainers 在自动化测试中运行 Docker 容器的指南。
适用场景
用户提到以下内容时,始终使用此技能:
- "testcontainers", "Testcontainer", "测试容器"
- "集成测试", "docker 测试"
- "数据库测试", "PostgreSQL test", "MySQL test"
- "Java Testcontainers", "Python Testcontainers"
- "测试环境搭建"
Java — Testcontainers
PostgreSQL 示例
@Testcontainers
@SpringBootTest
class OrderRepositoryTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@DynamicPropertySource
static void configure(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Test
void shouldSaveAndFindOrder() {
Order saved = repository.save(new Order(...));
assertThat(repository.findById(saved.getId())).isPresent();
}
}
Redis 示例
@Container
static GenericContainer<?> redis = new GenericContainer<>("redis:7-alpine")
.withExposedPorts(6379);
// Get connection string
String redisUrl = "redis://" + redis.getHost() + ":" + redis.getMappedPort(6379);
Kafka 示例
@Container
static KafkaContainer kafka = new KafkaContainer(
DockerImageName.parse("confluentinc/cp-kafka:7.6.0"));
String bootstrapServers = kafka.getBootstrapServers();
Python — testcontainers-python
import pytest
from testcontainers.postgres import PostgresContainer
from testcontainers.redis import RedisContainer
@pytest.fixture(scope="module")
def postgres():
with PostgresContainer("postgres:16-alpine") as pg:
yield pg.get_connection_url()
def test_database_connection(postgres):
import psycopg2
conn = psycopg2.connect(postgres)
assert conn.status == psycopg2.STATUS_READY
容器生命周期
// Singleton: one container for all tests
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
// Per-test: new container for each test
@Test
void test() {
try (var redis = new GenericContainer<>("redis:7")) {
redis.start();
// test...
} // auto-closed by try-with-resources
}
CI/CD 配置
# GitHub Actions — DinD (Docker-in-Docker)
jobs:
test:
runs-on: ubuntu-latest
services:
docker:
image: docker:27-dind
options: --privileged
steps:
- uses: actions/checkout@v4
- run: ./gradlew test
工作流 — 推荐集成流程
步骤 1:添加依赖:testImplementation 'org.testcontainers:testcontainers:1.20.6'
步骤 2:定义容器:@Container static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
步骤 3:注入配置:使用 @DynamicPropertySource 将容器连接信息注入 Spring 配置
步骤 4:编写测试:编写 @Test void shouldSaveAndFind() 业务测试
步骤 5:加速 CI:启用 withReuse(true) + GHA cache
注意事项 — 常见问题
- CI 启动缓慢:CI 中需要拉取容器镜像。→ 解决方法:在测试步骤之前添加
docker pull postgres:16-alpine进行预热;在.testcontainers.properties中启用withReuse(true)。 - CI 中的端口冲突:Testcontainers 会选择随机端口,因此不会冲突。但测试中硬编码的端口会导致失败。→ 解决方法:始终使用
container.getMappedPort(5432),不要硬编码端口号。 - 资源清理:Ryuk 会自动移除容器。在 CI 中,请确保配置了 DinD 或可访问 Docker socket。→ 解决方法:如果设置了
TESTCONTAINERS_RYUK_DISABLED=true,请添加@AfterAll清理;检查 CI 中是否挂载了 Docker socket。 - 静态容器与实例容器:静态
@Container字段会在整个类中共享一个容器。实例字段则会为每项测试创建容器。→ 解决方法:数据库使用静态容器(可共享状态);对隔离要求严格的测试使用实例容器;对于 JUnit 5,请检查@TestInstance(TestInstance.Lifecycle.PER_CLASS)。
边界 — 能力边界(适用与不适用场景)
| 分类 | 场景 | 说明 |
|---|---|---|
| ✅ 能做 | Java/Python 集成测试 | PostgreSQL/MySQL/Redis/Kafka 等容器化数据库测试 |
| ✅ 能做 | Spring Boot 测试 | @Testcontainers + @DynamicPropertySource 自动注入 |
| ✅ 能做 | CI 集成 | 在 GitHub Actions/Jenkins 中自动启动/清理 |
| ⚠️ 需条件 | 跨 JVM 复用 | 需配置 testcontainers.reuse.enable=true |
| ⚠️ 需条件 | 非 Java 语言测试 | 使用各语言对应的 Testcontainers 库 |
| ❌ 超范围 | 手动测试/调试 | 使用 docker-run |
| ❌ 超范围 | 生产数据库测试 | 连接生产实例,而不是容器 |
| ❌ 超范围 | 性能/压力测试 | 使用专用工具(JMeter/K6) |
不适用此技能的场景
| ❌ 跳过 | ✅ 改用 |
|---|---|
| 手动测试 | docker-run |
| 生产数据库测试 | docker-storage + 实际实例 |
| 模拟测试 | 使用 Mockito/unittest.mock |
| Docker 基础知识 | docker-basics |
安全与稳定性
- Testcontainers 使用随机端口,不会与运行中的服务发生端口冲突。
- 测试完成后,Ryuk 会自动清理容器。
- 切勿在生产代码中使用 Testcontainers;仅用于测试。
- 在本地开发中使用
withReuse(true)可加快测试速度(容器会在多次运行之间保留)。
📚 官方文档参考
| 文档 | 地址 |
|---|---|
| Testcontainers 概述 | https://docs.docker.com/testcontainers/ |
| Testcontainers for Java | https://java.testcontainers.org/ |
| Testcontainers Cloud | https://testcontainers.com/cloud/ |
| Spring Boot 集成 | https://java.testcontainers.org/modules/spring-boot/ |
| CI 配置 | https://java.testcontainers.org/supported_docker_environment/continuous_integration/ |
🧭 Docker 技能路线
📍 你在这里:
docker-testcontainers— 测试容器
← 上一步:docker-troubleshooting — 问题排查
→ 下一步:docker-ai-ml — AI/ML 工作负载
常见问题
Q1:如何快速上手此技能? A:参考上方的快速开始章节,按步骤操作即可。
Q2:遇到版本不兼容问题怎么办? A:检查依赖版本,使用 lock 文件锁定,参考常见问题章节。
Q3:如何在生产环境中使用? A:参考最佳实践章节,确保配置正确,并做好监控和日志记录。
Q4:如何优化性能? A:参考性能优化相关文档,使用缓存、索引等手段。
Q5:如何贡献或反馈问题? A:在 GitHub 仓库提交 Issue 或 Pull Request。
Q6:是否支持中文? A:支持中文文档和中文注释,详见国内适配章节。