使用Moq测试MyData类时GetData方法未执行且返回null
问题根因定位
你遇到的现象和异步调用写法无关,本质是Moq的默认拦截规则触发的典型踩坑:
- Moq创建Mock实例时,会对被Mock类的所有
virtual成员(无论public、protected访问修饰符)启用默认拦截:如果没有显式配置该成员的行为,就会直接拦截调用,返回成员类型的默认值(对应Task<string>的默认值就是null),完全不会执行原类中定义的方法逻辑。 - 你代码中作为测试目标的
GetData方法本身就是public virtual方法,创建出来的Mock实例会直接拦截这个方法的调用,根本不会触发原类里写的GetData逻辑,自然方法内部的断点无法命中,最终直接返回null。
修复方案
只要调整Mock的配置,让被拦截的GetData方法走原类的真实逻辑,同时保留对两个依赖方法的Mock配置即可:
- 方式一:在Mock初始化阶段开启
CallBase = true,告知Moq对未显式设置行为的成员,默认调用原类的实现 - 方式二:不对整个Mock开启全局CallBase,只针对
GetData方法单独配置调用原实现,精准控制行为 - 修正后的测试代码示例:
public void TestData() { string testData = "some data"; Mock<MyData> dataMock = new Mock<MyData>("path") { // 开启基类原方法调用 CallBase = true }; // 保留原有对依赖的受保护方法的Mock配置 dataMock.Protected().Setup<bool>("IsDataExpired").Returns(true); dataMock.Protected().Setup<Task<string>>("CreateData").ReturnsAsync(testData); var dataRes = dataMock.Object.GetData().Result; Assert.IsNotNull(dataRes); Assert.AreEqual(testData, dataRes); }
- 注意点:如果不想全局开启
CallBase,也可以单独对GetData配置:
dataMock.Setup(m => m.GetData()).CallBase();
这种写法的效果和全局开启CallBase一致,只对GetData方法放行原逻辑调用,其他未配置的虚方法还是走默认拦截规则。
内容的提问来源于stack exchange,提问作者CodeMonkey
相关产品推荐
相关产品推荐

