一、TestContainers 是什么?

TestContainers 是一个 Java 库(也有 Go、Python、.NET 等多语言版本),它能在单元测试 / 集成测试中,通过 Docker 容器快速创建真实的依赖服务(如 MySQL、Redis、Kafka、Elasticsearch 等),测试完成后自动销毁容器,解决了 “测试环境不一致”“本地搭环境麻烦” 的核心痛点。

简单来说:你不用手动安装 / 启动 MySQL 服务,写测试代码时,TestContainers 会自动拉取 MySQL 镜像、启动容器、配置连接,测试结束后自动删容器,全程无手动操作。

二、核心优势

  1. 环境一致性:本地、CI/CD、同事电脑用的都是相同版本的依赖服务,避免 “我这能跑,他那报错”。
  2. 真实测试:用真实的数据库 / 中间件测试,比 Mock 更贴近生产环境,能发现更多实际问题。
  3. 无侵入:测试结束自动清理容器,不会污染本地环境。
  4. 多语言支持: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. 运行测试的效果
  1. 运行测试类,TestContainers 会自动:
    • 检查本地 Docker 是否运行;
    • 拉取 mysql:8.0.36 镜像(首次运行需要下载,后续复用);
    • 启动 MySQL 容器,暴露随机端口(避免端口冲突);
    • 配置数据库连接参数;
  2. 执行测试逻辑(建表、插数据、查数据);
  3. 测试完成后,自动停止并删除容器,清理环境。

四、常用容器类型

除了 MySQL,TestContainers 支持几乎所有主流中间件:

表格

中间件 对应的 Container 类 核心用途
Redis RedisContainer 缓存测试
Kafka KafkaContainer 消息队列测试
Elasticsearch ElasticsearchContainer 搜索引擎测试
PostgreSQL PostgresContainer 关系型数据库测试
MongoDB MongoDBContainer 非关系型数据库测试

总结

  1. 核心价值:TestContainers 基于 Docker 为测试提供 “一次性、真实的依赖服务”,解决测试环境不一致问题,让集成测试更可靠。
  2. 使用前提:本地 / CI 环境必须安装并运行 Docker。
  3. 关键用法:引入对应容器依赖 → 定义容器实例 → 配置连接参数 → 编写测试逻辑,容器的启动 / 销毁可通过注解自动管理。
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐