为什么调用someMockInstance.Object会触发类构造函数?如何避免该问题?
问题解答
为什么访问 Mock<T>.Object 会触发原类构造函数
Moq 框架的核心实现原理是动态生成继承自被Mock类型T的代理类,当你首次访问Object属性时,Moq会完成代理类的实例化。
根据C#/.NET的类型系统规则,任何子类实例化时都会自动执行父类的构造函数链,哪怕这个子类是运行时动态生成的代理类也不例外。所以你访问mockFoo.Object时,代理类的实例化会触发父类Foo的构造函数执行。
避免触发构造函数的可行方案
- 优先基于接口做Mock(最推荐)
为业务类抽象对应的接口,比如你可以为Foo定义IFoo接口,将需要Mock的方法声明在接口中:
测试时直接Mock接口即可:public interface IFoo { string DoSomething(); } public class Foo : IFoo { public Foo() { // Init some stuff } public virtual string DoSomething() { // Blah } }var mockFoo = new Mock<IFoo>();,接口不存在构造函数,自然不会触发任何构造逻辑,这也是单元测试的公认最佳实践。 - 拆分构造函数的重逻辑
如果你确实无法抽取接口,必须Mock具体类,可以把构造函数中不需要在测试中执行的重逻辑拆分到独立的Init类方法中,业务代码中实例化后显式调用初始化方法,这样即使测试时构造函数被调用,也不会执行你想要规避的逻辑。
注意:只要你选择Mock具体类,就无法完全跳过原类构造函数的执行,这是.NET继承机制的固有规则限制,所有继承自该类的实例(包括动态代理实例)都必须执行父类构造逻辑。
内容的提问来源于stack exchange,提问作者Lee Tickett
相关产品推荐
相关产品推荐

