要模拟类型,它必须是一个接口(这也称为纯虚拟)或拥有虚拟成员(抽象成员也是虚拟的)。
根据这个定义,你可以模拟一切virtual.
本质上,动态模拟不要做任何你手工做不到的事情.
假设您正在针对这样的接口进行编程:
public interface IMyInterface
{
string Foo(string s);
}
您可以手动创建 IMyInterface 的特定于测试的实现,该实现忽略输入参数并始终返回相同的输出:
public class MyClass : IMyInterface
{
public string Foo(string s)
{
return "Bar";
}
}
但是,如果您想测试消费者如何响应不同的返回值,那么这会变得非常快地重复,所以不要编写代码测试双打您可以手动让框架为您动态创建它们。
想象一下,动态模拟确实编写了与上面的 MyClass 实现类似的代码(它们实际上并不编写代码,而是动态发出类型,但这是一个足够准确的类比)。
以下是如何使用 Moq 定义与 MyClass 相同的行为:
var mock = new Mock<IMyInterface>();
mock.Setup(x => x.Foo(It.IsAny<string>())).Returns("Bar");
在这两种情况下,创建对象时都会调用所创建类的构造函数。由于接口没有构造函数,因此这通常是默认构造函数(分别是 MyClass 和动态发出的类的)。
您可以对具体类型执行相同的操作,例如:
public class MyBase
{
public virtual string Ploeh()
{
return "Fnaah";
}
}
手动,您将能够从 MyBase 派生并重写 Ploeh 方法,因为它是虚拟的:
public class TestSpecificChild : MyBase
{
public override string Ploeh()
{
return "Ndøh";
}
}
动态模拟库可以做同样的事情,抽象方法也是如此。
但是,您无法编写覆盖非虚拟或内部成员的代码,动态模拟也不能。他们只能做你手工能做的事情。
警告:上面的描述对于大多数动态模拟都是正确的,但 TypeMock 除外,它是不同的并且......可怕。