【问题标题】:To mock an object, does it have to be either implementing an interface or marked virtual?要模拟一个对象,它必须是实现一个接口还是标记为虚拟的?
【发布时间】:2010-12-30 16:17:26
【问题描述】:

或者这个类也可以实现一个抽象类?

【问题讨论】:

标签: moq


【解决方案1】:

要模拟一个类型,它必须要么是一个接口(这也被称为是纯虚拟)或具有虚拟成员(抽象成员也是虚拟的)。

根据这个定义,你可以模拟所有虚拟的

从本质上讲,动态模拟不会做任何手工无法做到的事情

假设您正在针对这样的接口进行编程:

public interface IMyInterface
{
    string Foo(string s);
}

您可以手动创建 IMyInterface 的特定于测试的实现,该实现忽略输入参数并始终返回相同的输出:

public class MyClass : IMyInterface
{
    public string Foo(string s)
    {
        return "Bar";
    }
}

但是,如果您想测试消费者如何响应不同的返回值,这会变得非常重复,因此您可以让框架动态创建它们,而不是手动编写 Test Doubles给你。

想象一下,动态模拟确实编写了类似于上面的 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 除外,它是不同的并且......可怕。

【讨论】:

  • 还有一个更新的模拟库,Microsoft Moles,它可以做 TypeMock 所做的事情......它可以模拟所有内容,包括非虚拟、密封和静态方法。
【解决方案2】:

来自Stephen Walther's blog

您可以使用 Moq 从接口和现有类创建模拟。对类有一些要求。类不能被密封。此外,被模拟的方法必须标记为虚拟的。您不能模拟静态方法(使用适配器模式模拟静态方法)。

【讨论】:

  • 是的,但抽象类不是很像接口吗?嗯
  • 关键是虚函数,可以让mock动态生成可以调用的代理。
猜你喜欢
  • 1970-01-01
  • 2012-03-02
  • 2010-11-13
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 1970-01-01
  • 2013-02-18
相关资源
最近更新 更多