WebApplicationFactory 是启动真实内存内 ASP.NET Core 应用实例的集成测试工具,需正确配置入口类型、复用实例、处理认证、数据库隔离及第三方服务 Mock。

WebApplicationFactory 是集成测试的起点
它不是模拟容器,而是真正启动一个轻量级、内存内的 ASP.NET Core 应用实例,所有中间件、依赖注入、配置、路由都按真实逻辑运行——但不监听真实端口,也不依赖 IIS 或 Kestrel。这意味着你测的是“跑起来的程序”,不是一堆 Mock 对象拼凑的假象。
最简用法:var factory = new WebApplicationFactory(.NET 6+ 推荐指向 Program 类;若用传统 Startup 模式,则指向 Startup)。注意:必须确保 TEntryPoint 所在程序集能被当前测试项目引用,否则编译失败或运行时报 System.IO.FileNotFoundException。
- 不要在测试类构造函数里反复 new
WebApplicationFactory,它会创建独立应用上下文,开销大;应作为[ClassFixture]复用 - 若测试中修改了配置(如数据库连接字符串),需通过
WithWebHostBuilder()覆盖,直接改IConfiguration实例无效 - .NET 7+ 中若项目启用了
ImplicitUsings,测试项目也需保持一致,否则可能找不到WebApplicationFactory类型
HttpClient.GetFromJsonAsync 等扩展方法需要显式添加 System.Net.Http.Json
很多人写完 factory.CreateClient() 后直接调 client.GetFromJsonAsync,结果编译报错:“GetFromJsonAsync 未找到”。这不是 WebApplicationFactory 的问题,而是缺少 NuGet 包和 using。
- 必须安装
System.Net.Http.JsonNuGet 包(.NET 5+ 内置但需显式引用) - 必须加
using System.Net.Http.Json; - 该扩展方法底层调用
SendAsync并自动反序列化,但不会自动处理 401/403 等非成功状态码——遇到时抛HttpRequestException,需 try/catch 或用EnsureSuccessStatusCode() - 若 API 返回
ProblemDetails(如启用AddProblemDetails()),默认 JSON 反序列化会失败,建议用GetAsync()+ 手动读取response.Content.ReadAsStringAsync()再判断状态码
测试带认证的控制器要手动设置 Authorization Header 或注入 TestAuthHandler
WebApplicationFactory 默认不带任何认证上下文。即使你在 Startup 里配了 JWT Bearer 或 Cookie 认证,CreateClient() 发出的请求仍是匿名的。
- 最简单方式:给
HttpClient加 header:client.DefaultRequestHeaders.Authorization = new("Bearer", "valid.jwt.token");token 可用Microsoft.IdentityModel.Tokens.JwtSecurityTokenHandler在测试中快速生成 - 更可控方式:重写
ConfigureWebHost,用services.AddAuthentication().AddScheme,并在测试中用("TestScheme", _ => { }) client.DefaultRequestHeaders.Authorization = new("TestScheme", "dummy") - 切勿在测试中复用生产环境的密钥或签发服务——容易因时间偏移、密钥轮换导致 token 验证失败;用测试专用的
SymmetricSecurityKey就够了
数据库污染和事务回滚必须自己管理
WebApplicationFactory 不会自动帮你清库或开事务。如果你的 API 写了数据库,每次测试跑完数据就留在那里,下次测试可能因主键冲突、唯一约束或脏数据失败。
- 推荐方案:用
Sqlite InMemory数据库(UseSqlite("DataSource=:memory:")),并在每个测试前调context.Database.OpenConnection(); context.Database.EnsureCreated(); - 若必须用 SQL Server / PostgreSQL,可在
WithWebHostBuilder中替换IDbContextFactory,让每次测试获取全新上下文,并在Dispose时执行context.Database.EnsureDeleted() - 别依赖
TransactionScope自动回滚——它在某些 EF Core 版本和数据库驱动下不生效,尤其跨线程或异步调用时 - 如果 API 内部用了
SaveChangesAsync以外的持久化方式(如直接调用 Dapper 或原始 ADO.NET),事务隔离必须手动包裹,WebApplicationFactory完全不管这些
最难缠的其实是第三方服务耦合:邮件发送、消息队列、外部 HTTP 调用。它们不会因为你用了 WebApplicationFactory 就自动变成可测的。得在 ConfigureWebHost 里把对应服务替换成 Mock 或内存实现,而且要确保替换时机早于控制器被解析——否则依赖注入容器已经缓存了真实实例,Mock 就白注册了。










