.NET 6 + xUnit使用Test Containers集成测试卡住求助
问题:.NET 6 API xUnit集成测试卡在第一步(Test Containers容器已正常启动)
正在为.NET 6 API项目使用Test Containers运行xUnit集成测试,容器实例已正常启动,且能在浏览器中访问目标端点并获取响应,但xUnit测试始终卡在第一个测试步骤,无任何执行动作,相关截图如下:


测试代码
public class IntegrationTestWebAppFactory : WebApplicationFactory<Program>, IAsyncLifetime { private readonly IContainer _apiContainer; public HttpClient Client { get; private set; } public IntegrationTestWebAppFactory() { Console.WriteLine("initiating the factory"); _apiContainer = new ContainerBuilder() .WithImage("***.azurecr.io/weather.api:v1") .WithEnvironment("DOCKER_REGISTRY_URL", "***") .WithEnvironment("DOCKER_REGISTRY_USERNAME", "***") .WithEnvironment("DOCKER_REGISTRY_PASSWORD", "***") .WithPortBinding(8080, 80) .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(r => r.ForPort(8080))) .Build(); } public async Task InitializeAsync() { Console.WriteLine("InitializeAsync"); await _apiContainer.StartAsync().ConfigureAwait(false); Client = new HttpClient { BaseAddress = new Uri("http://localhost:8080/") }; Console.WriteLine("InitializeAsync done"); } async Task IAsyncLifetime.DisposeAsync() { Console.WriteLine("DisposeAsync"); await _apiContainer.DisposeAsync().ConfigureAwait(false); } } public class UnitTest1 : IClassFixture<IntegrationTestWebAppFactory> { private readonly IntegrationTestWebAppFactory _factory; public UnitTest1(IntegrationTestWebAppFactory factory) { _factory = factory; } [Fact] public async Task Should_Return_Forcast() { // Arrange if(_factory is null) { Console.WriteLine("factory is null"); return; } var client = _factory.Client; // Act var response = await client.GetAsync("http://localhost:8080/WeatherForecast"); response.EnsureSuccessStatusCode(); var responseString = await response.Content.ReadAsStringAsync(); Assert.NotEmpty(responseString); } }
问题排查与解决方案
1. 移除WebApplicationFactory的不必要继承
你同时继承了WebApplicationFactory<Program>并手动启动Test Containers容器,WebApplicationFactory本身会自动启动一个测试用Web实例,两者的初始化逻辑可能导致线程阻塞。如果你的目标是测试已构建的镜像,不需要继承WebApplicationFactory,直接实现IAsyncLifetime即可。
2. 优化等待策略
当前的等待策略仅检查端口连通性,建议明确指定测试端点路径并增加超时时间,确保容器内服务完全就绪:
.WithWaitStrategy(Wait.ForUnixContainer() .UntilHttpRequestIsSucceeded(r => r.ForPort(8080).ForPath("/WeatherForecast")) .WithTimeout(TimeSpan.FromMinutes(2)))
3. 调整异步上下文处理
移除InitializeAsync中.ConfigureAwait(false),避免线程上下文切换导致的初始化阻塞:
await _apiContainer.StartAsync();
4. 简化HttpClient请求地址
已设置BaseAddress的情况下,请求时使用相对路径即可,避免冗余的完整地址解析问题:
var response = await client.GetAsync("/WeatherForecast");
修改后的示例代码
public class IntegrationTestFixture : IAsyncLifetime { private readonly IContainer _apiContainer; public HttpClient Client { get; private set; } public IntegrationTestFixture() { Console.WriteLine("initiating the fixture"); _apiContainer = new ContainerBuilder() .WithImage("***.azurecr.io/weather.api:v1") .WithEnvironment("DOCKER_REGISTRY_URL", "***") .WithEnvironment("DOCKER_REGISTRY_USERNAME", "***") .WithEnvironment("DOCKER_REGISTRY_PASSWORD", "***") .WithPortBinding(8080, 80) .WithWaitStrategy(Wait.ForUnixContainer() .UntilHttpRequestIsSucceeded(r => r.ForPort(8080).ForPath("/WeatherForecast")) .WithTimeout(TimeSpan.FromMinutes(2))) .Build(); } public async Task InitializeAsync() { Console.WriteLine("InitializeAsync"); await _apiContainer.StartAsync(); Client = new HttpClient { BaseAddress = new Uri("http://localhost:8080/") }; Console.WriteLine("InitializeAsync done"); } public async Task DisposeAsync() { Console.WriteLine("DisposeAsync"); await _apiContainer.DisposeAsync(); } } public class UnitTest1 : IClassFixture<IntegrationTestFixture> { private readonly IntegrationTestFixture _fixture; public UnitTest1(IntegrationTestFixture fixture) { _fixture = fixture; } [Fact] public async Task Should_Return_Forcast() { // Arrange if (_fixture is null) { Console.WriteLine("fixture is null"); return; } var client = _fixture.Client; // Act var response = await client.GetAsync("/WeatherForecast"); response.EnsureSuccessStatusCode(); var responseString = await response.Content.ReadAsStringAsync(); // Assert Assert.NotEmpty(responseString); } }
内容的提问来源于stack exchange,提问作者Reza Shirazi
相关产品推荐
相关产品推荐

