ReSharper dotCover显示0%覆盖率但测试已执行代码的问题
我之前碰到过好几个和你一模一样的情况,你的测试明明能通过,但dotCover却显示这部分LINQ代码覆盖率为0,核心原因其实是EF Core的LINQ延迟执行特性加上你模拟DbSet的方式不对——听我给你拆解清楚:
为什么会出现这种情况?
1. LINQ延迟执行导致代码没真正跑起来
你写的LINQ查询(from a in context.Assessments join...)是表达式树,只有当调用SingleOrDefault()的时候才会触发执行。但如果你的AsDbSetMock()扩展方法只是把List转换成普通的可查询集合,Moq会直接返回你预设的内存数据,根本不会去解析执行你写的那串join、where逻辑。也就是说,测试通过只是因为你预设的数据符合预期,但你写的LINQ代码其实根本没被执行过,dotCover自然会标记为0%覆盖率。
2. 模拟DbSet未适配EF Core的查询管道
EF Core的DbSet背后有自己的查询提供器,会把LINQ表达式树转换成SQL(哪怕是内存数据库也会走表达式树解析)。而普通的内存集合查询是直接在CLR里遍历集合,完全不走EF Core的表达式树处理流程。dotCover追踪的是你写的LINQ代码对应的IL指令,这部分没被触发的话,就不会被统计为已覆盖。
怎么解决?
方案一:改用EF Core内存数据库(推荐)
放弃手动Mock DbSet,直接用EF Core的InMemory数据库来做测试,这样你的LINQ查询会真正经过EF Core的查询管道,dotCover就能正确追踪到覆盖率。修改后的测试代码大概是这样:
[TestMethod] public void It_should_return_true_if_a_report_has_been_requested_for_the_givenassessment() { const int assessmentId = 1; var responseId = Guid.NewGuid(); // 配置内存数据库选项 var dbOptions = new DbContextOptionsBuilder<ICViewClientContext>() .UseInMemoryDatabase(databaseName: $"Test_ReportRequested_{Guid.NewGuid()}") // 用唯一名称避免测试间干扰 .Options; // 初始化测试数据 using (var context = new ICViewClientContext(dbOptions)) { context.Assessments.Add(new Assessments { AssessmentId = assessmentId, PublicId = responseId }); context.Registrations.Add(new Registrations { AssessmentId = assessmentId, ReportRequested = 1 }); context.SaveChanges(); } // 模拟IClientDatabase返回内存上下文 var mockClientDatabase = new Mock<IClientDatabase>(); mockClientDatabase.Setup(x => x.GetContext(1)).Returns(new ICViewClientContext(dbOptions)); var query = new Queries.Assessments.SelectIsReportRequested(2, responseId); var handler = new Queries.Assessments.SelectIsReportRequestedHandler(mockClientDatabase.Object); var result = handler.Execute(query); Assert.AreEqual(true, result); }
方案二:正确模拟EF Core的DbSet查询
如果你坚持要用Moq,那不能随便用个AsDbSetMock()就完事,需要让Mock能处理EF Core的表达式树。可以用专门的EF Core测试Moq库,比如EntityFrameworkCore.Testing.Moq,它能帮你正确模拟DbSet的查询行为,确保你的LINQ表达式树被解析执行。
验证小技巧
你可以在你的LINQ查询代码里加个断点,运行测试的时候看看断点会不会触发。如果断点没命中,那百分百是你的LINQ代码没被执行,这就是覆盖率为0的直接证据。
内容的提问来源于stack exchange,提问作者Ben Thomson

