使用NSubstitute验证Mock DbContext的Add方法调用失败问题
解决DbContext Add方法验证失败的问题
你遇到的核心问题是DbContext.Add是EF自带的非虚方法,NSubstitute无法拦截非虚方法的调用——哪怕实际代码执行了Add,Substitute也捕获不到这个调用行为,所以测试会提示无匹配调用。
以下是两种正确的验证方式:
方式一:验证对应DbSet的Add方法
业务代码中调用context.Add<ChangeLog>(entity)本质上会转调context.Set<ChangeLog>().Add(entity),因此可以mock对应的DbSet来验证:
// Mock ChangeLog对应的DbSet var changeLogSet = Substitute.For<DbSet<ChangeLog>, IQueryable<ChangeLog>>(); var context = Substitute.For<LampContext>(); // 将mock的DbSet绑定到上下文 context.Set<ChangeLog>().Returns(changeLogSet); // 调用触发Add操作的业务代码 // 验证DbSet的Add方法被调用1次,参数为任意ChangeLog实例 changeLogSet.Received(1).Add(Arg.Any<ChangeLog>());
方式二:通过接口抽象DbContext行为
定义包含Add方法的接口,让你的LampContext实现该接口,之后mock接口而非直接mock DbContext:
// 定义抽象接口 public interface ILampContext { void Add<TEntity>(TEntity entity) where TEntity : class; // 根据业务需求添加其他需要的DbContext方法 } // 让LampContext实现接口 public class LampContext : DbContext, ILampContext { // 原有DbContext的实现代码 } // 测试时mock接口 var context = Substitute.For<ILampContext>(); // 调用业务代码 // 直接验证接口的Add方法调用 context.Received(1).Add(Arg.Any<ChangeLog>());
注意事项
- 方式一中要确保业务代码的Add调用对应到正确的DbSet类型;
- 泛型方法验证时,
Arg.Any<ChangeLog>的类型要与实际传入的实体类型完全匹配。
内容的提问来源于stack exchange,提问作者Gargoyle
相关产品推荐
相关产品推荐

