.NET使用MSTest时无法停止Testcontainers容器的问题
Testcontainers + MSTest + SQL Server集成测试问题解决
一、测试挂起的核心原因及修复
测试挂起、后续代码不执行,主要是两个问题:
- 环境变量配置错误:SQL Server容器的官方环境变量不是你写的
User Id、Database,必须设置ACCEPT_EULA=Y(同意许可)和SA_PASSWORD(SA账户密码),否则容器内的SQL Server无法正常启动,测试会一直等待。 - 误用通用容器:
TestcontainersContainer是通用容器,没有内置SQL Server的就绪检测逻辑,StartAsync只会启动容器进程,但不会等待数据库真正可用,导致后续测试代码无法执行。应该用专门的MsSqlContainer,它会自动检测数据库是否就绪。
二、正确的容器配置与测试流程
- 先安装必要的NuGet包:
Testcontainers.MsSql(专用SQL Server容器包)和MSTest.TestFramework。 - 把容器改为实例字段(不要用静态字段),避免类加载时提前初始化导致生命周期不匹配。
- 用
MsSqlBuilder构建容器,它会自动处理正确的环境变量和就绪检测。
三、数据库初始化与SQL脚本执行
初始化数据库有两种简单方式:
- 直接执行SQL脚本:用
MsSqlContainer的ExecuteScriptAsync方法,直接传入SQL语句或脚本内容。 - ADO.NET连接操作:通过容器提供的连接字符串,用
SqlConnection连接数据库,执行初始化或查询。
四、完整修复后的代码
[TestClass] public class WithFixtureData { private MsSqlContainer _dbContainer; [TestInitialize] public async Task StartContainer() { // 构建专用SQL Server容器,自动处理环境变量和就绪检测 _dbContainer = new MsSqlBuilder() .WithImage("mcr.microsoft.com/mssql/server:2022-latest") .WithPassword("YourSTRONG!Passw0rd") .WithCleanUp(true) // 测试结束自动清理容器 .Build(); // 启动容器,等待数据库就绪后才继续执行 await _dbContainer.StartAsync(); } [TestMethod] public async Task ShouldBringCorrectFixturesBack() { // 1. 执行SQL脚本初始化表和数据 await _dbContainer.ExecuteScriptAsync(@" CREATE TABLE TestTable (Id INT PRIMARY KEY, Name NVARCHAR(50)); INSERT INTO TestTable VALUES (1, 'SampleData'); "); // 2. 连接数据库查询并断言 await using var connection = new SqlConnection(_dbContainer.GetConnectionString()); await connection.OpenAsync(); await using var command = new SqlCommand("SELECT Name FROM TestTable WHERE Id = 1", connection); var retrievedName = await command.ExecuteScalarAsync() as string; Assert.AreEqual("SampleData", retrievedName); } [TestCleanup] public async Task DisposeContainer() { if (_dbContainer != null) { await _dbContainer.StopAsync(); await _dbContainer.DisposeAsync(); } } }
关键细节说明
- 不用手动配置
ACCEPT_EULA:MsSqlBuilder会自动添加这个环境变量,无需手动设置。 GetConnectionString()方法:直接生成可用的连接字符串,包含正确的服务器地址(容器映射的端口)、用户名和密码,不用自己拼接。- 实例字段替代静态字段:静态容器会在类加载时创建,可能在多个测试方法间共享,导致测试污染;用实例字段可以保证每个测试方法都有独立的容器实例。
内容的提问来源于stack exchange,提问作者clattenburg cake
相关产品推荐
相关产品推荐

