Spring Boot 4.0 Testcontainers 集成测试实战
前言
内存数据库无法验证 PostgreSQL 方言、Flyway 脚本、驱动版本和容器网络。手工启动一个数据库再跑测试,又会把“本机能跑”变成隐藏前置条件。
Testcontainers 让测试自己启动 PostgreSQL,执行真实迁移和 SQL,测试结束后自动清理。
读者需要完成 Flyway、MyBatis/JPA 和测试章节,并安装可运行的 Docker。源码位于 dvsusan/spring-boot4-demo。
最终结果
新增测试:
PostgresTestcontainersIntegrationTest测试会启动 postgres:17-alpine,让 Spring Boot 自动连接容器,执行 Flyway 迁移,并查询 flyway_schema_history。

图 1:容器生命周期由测试框架管理,Docker 不可用时明确跳过,不能伪装成通过。
第 1 步:添加 Testcontainers 依赖
<!-- Spring Boot 自动把测试容器暴露为应用服务连接。 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>项目固定 Testcontainers 1.21.4。
第 2 步:检查 Docker
docker version
docker infodocker version 成功但 docker info 失败,通常表示命令行存在而 Docker daemon 没有运行。Testcontainers 需要 daemon,而不只是 Docker CLI。
第 3 步:声明 PostgreSQL 容器
@Container
@ServiceConnection
static final PostgreSQLContainer<?> POSTGRES =
new PostgreSQLContainer<>(DockerImageName.parse("postgres:17-alpine"));@ServiceConnection 会把容器地址、端口、用户名和密码注入 Spring Boot,不需要在测试类里手写 DynamicPropertySource。
容器使用固定主版本 17,避免 latest 在某次构建时引入不可复现变化。
第 4 步:配置测试启动条件
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ActiveProfiles("db")
@Testcontainers(disabledWithoutDocker = true)
class PostgresTestcontainersIntegrationTest {
}disabledWithoutDocker=true 明确表达环境限制。CI 要求必须执行容器测试时,不应长期允许跳过,而应为 CI 安装 Docker 并让测试真正运行。
第 5 步:验证应用和迁移
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void flywayRunsInsideContainerDatabase() {
Integer migrations = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM flyway_schema_history WHERE success = true",
Integer.class
);
assertThat(migrations).isEqualTo(3);
}这条断言同时证明容器启动、Spring 上下文、数据源、PostgreSQL 驱动和 Flyway 脚本链路都成功。
第 6 步:运行测试
mvn -pl demo-web -am \
-Dtest=PostgresTestcontainersIntegrationTest \
-Dsurefire.failIfNoSpecifiedTests=false \
test有 Docker 时,日志会出现容器启动、数据库 ready 和测试通过。当前验证环境没有 Docker socket,实际结果为:
Tests run: 1, Failures: 0, Errors: 0, Skipped: 1这里如实记录为“跳过”,不能写成 PostgreSQL 容器测试已经成功执行。
Testcontainers 适合测什么?
- 真实 PostgreSQL、MySQL 方言和 SQL。
- Flyway/Liquibase 迁移。
- Kafka、RabbitMQ、Redis 等协议行为。
- 应用与中间件版本兼容性。
纯计算逻辑不应全部搬进容器测试。单元测试更快,容器测试负责验证真实依赖边界。
常见问题排查
| 现象 | 原因 | 处理方式 |
|---|---|---|
找不到 /var/run/docker.sock | Docker Desktop/daemon 未运行 | 启动 Docker 后重试 |
| 镜像下载失败 | 网络或仓库限流 | 配置镜像代理或预拉取镜像 |
| 测试一直等待端口 | 容器启动失败 | 查看容器日志和健康检查 |
| Spring 仍连 H2 | @ServiceConnection 未生效 | 检查 Testcontainers 依赖和测试 profile |
| 本地跳过但 CI 也跳过 | CI 没有 Docker | CI 安装 Docker,移除默认跳过策略 |
练习题
增加一个 Testcontainers Redis 测试,缓存写入后从另一个连接读取;再让 PostgreSQL 和 Redis 同时启动,验证应用关闭时连接和容器都能正常清理。验收标准是连续运行测试三次无残留容器。
总结
Testcontainers 把基础设施依赖变成测试代码的一部分。真实容器提供高可信度,明确跳过和 CI 约束保证结果不会被误读。
第七章完成后,项目已经具备异步、容错、性能、AI 和真实依赖测试能力。
上一节:Spring AI 2.0 知识库客服
相关阅读:Flyway 数据库迁移
相关阅读:常用 Docker 命令
返回课程目录
13 个企业级实战项目 · 源码 + 教程 + 答疑
简历包装指导AI Agent 实战高并发·微服务Offer 导向持续更新3000+ 同行交流1V1 答疑3 天包退
覆盖高并发、微服务、分布式与 AI Agent:100万QPS短链、企业智能知识库、商城微服务、SaaS点餐、秒杀、刷题小程序、代码生成器、AI Agent 等。券后 ¥129(原价 ¥159),不满意 3 天包退。
