.NET 6无显式Main方法的Program.cs如何编写测试用例
.NET 6顶层语句Program.cs的测试覆盖实现方案
.NET 6的顶层语句编译时会自动生成隐式的Program类,不需要显式写Main方法,要覆盖这部分代码只需要两步:
- 第一步:暴露Program类访问入口
在你的Web项目Program.cs文件的最末尾,添加一行分部类声明,不需要修改任何原有业务代码:
// 所有原有顶层语句写完之后加这行就行 public partial class Program { }
这行代码不会改变原有运行逻辑,只是把编译器生成的Program类访问级别设为公开,允许测试项目访问。如果不想公开Program类,也可以在Web项目的AssemblyInfo.cs里加[assembly: InternalsVisibleTo("你的测试项目程序集名")],让测试项目能访问internal级别的Program类。
- 第二步:用WebApplicationFactory构建测试宿主执行注册逻辑
测试项目引用Web项目后,通过WebApplicationFactory<Program>引导测试版应用宿主,启动过程会完整执行Program.cs里所有服务注册、中间件配置、路由映射的代码,这部分代码自然会被覆盖率工具统计到。
xUnit测试用例示例:
public class ServiceRegistrationTests { [Fact] public void 核心服务注册正常() { // 构建测试宿主,自动执行Program.cs所有顶层逻辑 var appFactory = new WebApplicationFactory<Program>(); var services = appFactory.Services; // 验证控制器服务注册成功 var controllerService = services.GetService<IActionDescriptorCollectionProvider>(); Assert.NotNull(controllerService); // 验证自定义AddServices扩展方法注册的服务可正常解析 // 替换成你自己的服务接口即可 // var customService = services.GetService<ICustomService>(); // Assert.NotNull(customService); } [Fact] public void 所有注册服务无解析错误() { var appFactory = new WebApplicationFactory<Program>(); var services = appFactory.Services; var serviceDescriptors = services.GetRequiredService<IServiceCollection>(); foreach (var descriptor in serviceDescriptors) { // 跳过开放泛型、框架内置服务,避免误报 if (descriptor.ServiceType.IsGenericTypeDefinition || descriptor.ServiceType.Assembly == typeof(IHost).Assembly) { continue; } var instance = services.GetService(descriptor.ServiceType); Assert.NotNull(instance); } } }
这种方案不需要把顶层语句改回传统的Main方法写法,也不需要额外抽离服务注册逻辑到单独类库,就能完整覆盖Program.cs里的所有配置代码。
内容的提问来源于stack exchange,提问作者Sangram Patil
相关产品推荐
相关产品推荐

