WebApplicationFactory 默认不支持并发测试,需为每个任务调用 CreateClient() 获取独立 HttpClient;避免复用客户端、检查单例服务线程安全、使用唯一内存数据库名。
直接在多个线程或 Task 中复用同一个 WebApplicationFactory 实例发起 HTTP 请求,大概率会遇到连接复用冲突、HTTP/2 流错乱、或 HttpRequestException: Error while copying content to a stream。这是因为 WebApplicationFactory 内部的 TestServer 虽然线程安全,但其默认配置的 HttpClient 实例(通过 CreateClient() 返回)**共享连接池且未隔离请求上下文**,尤其在高并发短时密集调用下容易触发底层 HttpHandler 状态竞争。
不要复用 CreateClient() 返回的单个 HttpClient 对象。每次并发请求前都应调用一次 CreateClient(),让 WebApplicationFactory 为你生成带独立连接管理的新客户端。
CreateClient() 是轻量操作,不重建应用或服务器,只新建 HttpClient 和关联的 TestServer 连接句柄HttpClient,需确保它被正确配置为支持并发(例如设置 MaxConnectionsPerServer),但不如直接用 CreateClient() 简洁可靠[Theory] + Parallelizable 或 Task.WhenAll 场景中,务必在每个 Task 内部调用 CreateClient()
var factory = new WebApplicationFactory(); await Task.WhenAll(Enumerable.Range(0, 10).Select(async _ => { // ✅ 正确:每个任务独立获取 client using var client = factory.CreateClient(); var response = await client.GetAsync("/api/values"); response.EnsureSuccessStatusCode(); }));
TestServer 内部使用同步上下文模拟 ASP.NET Core 的请求生命周期,但在高并发下若测试代码意外捕获并重用 SynchronizationContext(比如在 UI 测试项目中引入了 WinForms/WPF 引用),可能引发死锁或响应延迟。xUnit 默认无同步上下文,但某些自定义测试基类或第三方断言库可能干扰。
System.Windows.Forms 或 PresentationCore
Task.Wait() 或 Result —— 必须用 await
WebApplicationFactory 派生类中重写 CreateWebHostBuilder() 并添加日志中间件,观察并发请求是否被串行化处理WebApplicationFactory 启动的是完整应用,包括所有注册的单例服务(如 IMemoryCache、数据库上下文、事件总线等)。并发请求共享这些实例,若服务内部状态非线程安全(例如手动实现的静态计数器、未加锁的字典写入),会导致间歇性失败。
Program.cs 中是否将有状态对象注册为 AddSingleton 却未做同步保护AddDbCon
text(o => o.UseInMemoryDatabase(...))),并确保每个测试用唯一数据库名(如 Guid.NewGuid().ToString())真正难排查的并发问题往往不出在 WebApplicationFactory 本身,而在于你没意识到某个 Singleton 服务正被十个请求同时修改同一块内存。