在C#的集成测试场景中,我们经常需要依赖MySQL、Redis、RabbitMQ等外部服务,手动搭建和维护这些测试环境不仅繁琐,还容易出现环境不一致导致测试结果不可靠的问题。TestContainers通过Docker容器技术,让我们可以在测试执行时动态创建所需的服务容器,测试完成后自动清理,完美解决了上述痛点。

TestContainers基础配置
首先需要在C#测试项目中引入TestContainers相关的NuGet包,以使用MySQL容器为例,需要安装TestContainers和TestContainers.MySql两个包。安装完成后,就可以在测试类中初始化容器实例。
以下是基础的容器初始化代码:
using TestContainers.Container;
using TestContainers.MySql;
// 创建MySQL容器构建器
var mySqlBuilder = new MySqlBuilder()
.WithImage("mysql:8.0") // 指定MySQL镜像版本
.WithPassword("test_password") // 设置root用户密码
.WithDatabase("test_db"); // 初始化数据库名称
// 构建并启动容器
await using var mySqlContainer = await mySqlBuilder.Build();
await mySqlContainer.StartAsync();
// 获取容器连接字符串
string connectionString = mySqlContainer.GetConnectionString();
常用容器使用场景
关系型数据库测试
除了MySQL,TestContainers还支持PostgreSQL、SQL Server等常见关系型数据库,使用方式和MySQL类似,只需要替换对应的构建器即可。比如使用PostgreSQL时,引入TestContainers.PostgreSql包,使用PostgreSqlBuilder构建容器。
以下是一个使用PostgreSQL容器进行数据操作的测试示例:
using System.Data;
using Npgsql;
using TestContainers.PostgreSql;
[Test]
public async Task PostgreSql_Container_Test()
{
// 初始化PostgreSQL容器
var pgBuilder = new PostgreSqlBuilder()
.WithImage("postgres:15")
.WithPassword("pg_test_pwd")
.WithDatabase("pg_test_db");
await using var pgContainer = await pgBuilder.Build();
await pgContainer.StartAsync();
// 使用容器连接字符串创建连接
using var connection = new NpgsqlConnection(pgContainer.GetConnectionString());
await connection.OpenAsync();
// 执行建表语句
using var command = connection.CreateCommand();
command.CommandText = "CREATE TABLE test_user (id INT PRIMARY KEY, name VARCHAR(50))";
await command.ExecuteNonQueryAsync();
// 验证表是否创建成功
command.CommandText = "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'test_user'";
var result = (long)await command.ExecuteScalarAsync();
Assert.AreEqual(1, result);
}
中间件服务测试
对于Redis、RabbitMQ这类中间件,TestContainers同样提供了对应的支持包。以Redis为例,安装TestContainers.Redis包后,可以快速启动Redis容器进行缓存相关测试。
using StackExchange.Redis;
using TestContainers.Redis;
[Test]
public async Task Redis_Container_Test()
{
// 初始化Redis容器
var redisBuilder = new RedisBuilder()
.WithImage("redis:7.0");
await using var redisContainer = await redisBuilder.Build();
await redisContainer.StartAsync();
// 连接Redis容器
var redis = await ConnectionMultiplexer.ConnectAsync(redisContainer.GetConnectionString());
var db = redis.GetDatabase();
// 测试写入和读取
await db.StringSetAsync("test_key", "test_value");
var value = await db.StringGetAsync("test_key");
Assert.AreEqual("test_value", value.ToString());
}
测试生命周期管理
在实际的测试项目中,我们通常不会在每个测试方法中单独启动和停止容器,而是借助测试框架的生命周期机制,在测试类初始化时启动容器,所有测试执行完成后销毁容器,避免重复创建容器的开销。
以xUnit测试框架为例,可以通过IAsyncLifetime接口管理容器生命周期:
using Xunit;
using TestContainers.MySql;
public class MySqlIntegrationTest : IAsyncLifetime
{
private MySqlContainer _mySqlContainer;
// 测试类初始化时启动容器
public async Task InitializeAsync()
{
var builder = new MySqlBuilder()
.WithImage("mysql:8.0")
.WithPassword("test_pwd")
.WithDatabase("test_db");
_mySqlContainer = await builder.Build();
await _mySqlContainer.StartAsync();
}
// 测试类销毁时停止容器
public async Task DisposeAsync()
{
if (_mySqlContainer != null)
{
await _mySqlContainer.StopAsync();
await _mySqlContainer.DisposeAsync();
}
}
[Fact]
public async Task Test_MySql_Connection()
{
// 使用容器连接字符串进行测试
var connStr = _mySqlContainer.GetConnectionString();
Assert.NotNull(connStr);
}
}
注意事项
- 使用TestContainers前需要确保本地环境已经安装并启动了Docker,否则无法拉取和启动容器。
- 如果测试过程中需要自定义容器的端口映射、挂载卷等配置,可以通过构建器的对应方法实现,比如
WithPortBinding方法可以映射容器端口到宿主机。 - 容器启动需要一定时间,如果测试执行时提示连接失败,可以适当增加连接重试逻辑,避免因为容器未完全启动导致测试失败。
- 测试完成后要确保容器被正确销毁,避免残留容器占用系统资源,使用
await using语法可以自动释放容器资源。
TestContainersC#容器化集成测试集成测试修改时间:2026-07-05 03:21:25