Mock接口转换为TestManager实际类时返回null的技术问询
好的,咱们来拆解一下这个问题——你遇到的Mock失效本质是Moq生成的代理对象和实际类的类型不匹配导致的,我来给你讲清楚原因和解决办法:
你用Mock<ITestManager>创建的对象,是Moq动态生成的实现了ITestManager接口的代理类实例,它和TestManager没有任何继承关系。所以当你在待测试方法里用as TestManager做类型转换时,必然会返回null——这就导致你之前Mock的配置完全没被用到。
方案1:修改待测试代码(最推荐,符合设计原则)
你的待测试代码违反了依赖倒置原则:应该依赖抽象(接口)而非具体实现(TestManager类)。把这段代码:
ITestManager lookupManager = this.container.Resolve<ITestManager>() as TestManager;
改成直接使用接口:
ITestManager lookupManager = this.container.Resolve<ITestManager>();
这样Mock对象就能正常工作了,因为它本身就实现了ITestManager接口,不需要做多余的类型转换。这不仅解决了测试问题,还让你的代码耦合度更低,更易维护。
方案2:无法修改待测试代码时的替代方案
如果因为遗留代码等原因不能修改待测试方法,那你需要生成一个TestManager类型的Mock实例:
方式A:直接Mock具体类TestManager
如果TestManager中的someMethod是虚方法(或者TestManager是抽象类),可以直接Mock这个具体类:
var lookupManager = new Mock<TestManager>(); // Setup虚方法的返回值 lookupManager.Setup(p => p.someMethod()).Returns("SomeDummyValue"); // 注册到容器(注意类型要匹配) unitycontainer.RegisterInstance<ITestManager>(lookupManager.Object); // 或者如果容器需要直接解析TestManager类型: // unitycontainer.RegisterInstance<TestManager>(lookupManager.Object);
此时从容器解析出来的对象是Moq生成的TestManager子类实例,用as TestManager转换会成功,Mock的配置也能生效。
⚠️ 注意:这种方式要求你要Mock的方法是虚方法,否则Moq无法拦截并替换它的返回值——因为Moq是通过生成子类重写虚方法来实现Mock逻辑的。
方式B:自定义可测试的子类
如果TestManager的方法不是虚方法,无法直接用MoqMock具体类,你可以自己写一个继承自TestManager的子类,重写需要Mock的方法:
public class TestableTestManager : TestManager { // 前提是TestManager允许重写这个方法(比如方法是virtual或abstract) public override string someMethod() { return "SomeDummyValue"; } }
然后把这个子类实例注册到容器:
unitycontainer.RegisterInstance<ITestManager>(new TestableTestManager());
这样转换为TestManager也能成功,同时得到你需要的返回值。如果方法连重写都不允许,那只能考虑用更底层的篡改工具(比如Microsoft Fakes),不过这种方式成本较高,不推荐优先使用。
内容的提问来源于stack exchange,提问作者V J

