大多数模拟框架只能模拟接口,有些可以模拟类的虚拟方法。一些 Java 模拟框架甚至能够模拟静态类。
例如犀牛模拟:
var mock = MockRepository.GenerateMock<..>();
生成模拟方法中有什么“魔法”?C# 模拟框架不允许模拟静态类有什么原因吗?或者这只是一个“设计选择”?
大多数模拟框架只能模拟接口,有些可以模拟类的虚拟方法。一些 Java 模拟框架甚至能够模拟静态类。
例如犀牛模拟:
var mock = MockRepository.GenerateMock<..>();
生成模拟方法中有什么“魔法”?C# 模拟框架不允许模拟静态类有什么原因吗?或者这只是一个“设计选择”?
研究这些框架的源代码并自己找到答案实际上是非常有趣和令人着迷的。Rhino Mocks以及Moq和许多其他软件都是开源的。我肯定会建议潜入其中之一。
至于内部实现(从这里):
但是,该框架不能模拟非虚拟方法,因此我们需要将 TouchIron 方法设为虚拟。原因很深:Rhino Mocks 使用Castle Dynamic Proxy来处理代理它需要模拟的类型,而 Dynamic Proxy 无法拦截对非虚拟、非抽象方法的调用。
大多数开源模拟框架都使用Castle Windsor 的动态代理在运行时自动生成一个类型,该类型可以通过预期的行为进行编程。这就是为什么大多数这些框架都需要一个接口或一个抽象类的原因——它们无法模拟任何不是虚拟方法的东西。
还有其他(商业)模拟框架确实可以模拟静态和常规(密封)类,包括基于非托管CLR Profiler API的 CLR 类型。基本上,模拟框架充当分析器,并且能够在 JIT 编译之前修改内存中的 MSIL 指令。这就是它能够用预定义值替换任何方法的主体的方式。其中一些框架是免费的*(Microsoft Fakes,Visual Studio 2012 Ultimate 的一部分),另一些是付费产品,例如Typemock。
几乎所有的 .NET 模拟框架都利用了Castle Windsor 的动态代理功能。我会建议通过其中一些。