快速上手TestContainers
·
一、TestContainers 是什么?
TestContainers 是一个 Java 库(也有 Go、Python、.NET 等多语言版本),它能在单元测试 / 集成测试中,通过 Docker 容器快速创建真实的依赖服务(如 MySQL、Redis、Kafka、Elasticsearch 等),测试完成后自动销毁容器,解决了 “测试环境不一致”“本地搭环境麻烦” 的核心痛点。
简单来说:你不用手动安装 / 启动 MySQL 服务,写测试代码时,TestContainers 会自动拉取 MySQL 镜像、启动容器、配置连接,测试结束后自动删容器,全程无手动操作。
二、核心优势
- 环境一致性:本地、CI/CD、同事电脑用的都是相同版本的依赖服务,避免 “我这能跑,他那报错”。
- 真实测试:用真实的数据库 / 中间件测试,比 Mock 更贴近生产环境,能发现更多实际问题。
- 无侵入:测试结束自动清理容器,不会污染本地环境。
- 多语言支持:Java、Python、Go、Node.js 等主流语言都有适配。
三、快速上手(Java + Spring Boot + MySQL 示例)
1. 前置条件
- 本地安装 Docker(TestContainers 依赖 Docker 运行容器)。
- 项目引入 Maven/Gradle 依赖。
2. 引入依赖(Maven)
<!-- TestContainers 核心依赖 -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<!-- MySQL 容器专用依赖 -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<!-- JUnit 5 依赖(测试框架) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<!-- Spring Boot Test 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
3. 编写测试代码
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.springframework.jdbc.core.JdbcTemplate;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
// 启用 TestContainers 支持
@Testcontainers
// 让 BeforeAll/AfterAll 可以用非静态方法(简化代码)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MySQLContainerTest {
// 定义 MySQL 容器,指定镜像版本(推荐固定版本,避免镜像更新导致测试失败)
@Container
private final MySQLContainer<?> mysqlContainer = new MySQLContainer<>(DockerImageName.parse("mysql:8.0.36"))
// 设置数据库名、用户名、密码
.withDatabaseName("test_db")
.withUsername("test_user")
.withPassword("test_pass");
private JdbcTemplate jdbcTemplate;
// 测试前初始化:启动容器 + 创建 JdbcTemplate
@BeforeAll
void setUp() throws SQLException {
// 启动容器(@Container 注解会自动启动,这里手动启动也可以)
mysqlContainer.start();
// 获取容器的数据库连接信息,创建数据源
DataSource dataSource = mysqlContainer.createDataSource();
try (Connection conn = dataSource.getConnection()) {
assertNotNull(conn, "数据库连接不应为空");
}
// 初始化 JdbcTemplate 用于操作数据库
jdbcTemplate = new JdbcTemplate(dataSource);
}
// 测试核心逻辑:创建表 + 插入数据 + 查询验证
@Test
void testMySQLContainer() {
// 1. 创建测试表
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user (id INT PRIMARY KEY, name VARCHAR(255))");
// 2. 插入数据
jdbcTemplate.update("INSERT INTO user (id, name) VALUES (1, ?)", "TestContainers");
// 3. 查询数据并验证
String userName = jdbcTemplate.queryForObject(
"SELECT name FROM user WHERE id = 1",
String.class
);
assertEquals("TestContainers", userName, "查询结果应匹配插入的用户名");
}
// 测试后清理:停止容器(@Container 注解会自动停止,这里手动停止也可以)
@AfterAll
void tearDown() {
mysqlContainer.stop();
}
}
4. 运行测试的效果
- 运行测试类,TestContainers 会自动:
- 检查本地 Docker 是否运行;
- 拉取
mysql:8.0.36镜像(首次运行需要下载,后续复用); - 启动 MySQL 容器,暴露随机端口(避免端口冲突);
- 配置数据库连接参数;
- 执行测试逻辑(建表、插数据、查数据);
- 测试完成后,自动停止并删除容器,清理环境。
四、常用容器类型
除了 MySQL,TestContainers 支持几乎所有主流中间件:
表格
| 中间件 | 对应的 Container 类 | 核心用途 |
|---|---|---|
| Redis | RedisContainer |
缓存测试 |
| Kafka | KafkaContainer |
消息队列测试 |
| Elasticsearch | ElasticsearchContainer |
搜索引擎测试 |
| PostgreSQL | PostgresContainer |
关系型数据库测试 |
| MongoDB | MongoDBContainer |
非关系型数据库测试 |
总结
- 核心价值:TestContainers 基于 Docker 为测试提供 “一次性、真实的依赖服务”,解决测试环境不一致问题,让集成测试更可靠。
- 使用前提:本地 / CI 环境必须安装并运行 Docker。
- 关键用法:引入对应容器依赖 → 定义容器实例 → 配置连接参数 → 编写测试逻辑,容器的启动 / 销毁可通过注解自动管理。
更多推荐
所有评论(0)