C# 为什么要使用模拟框架?

C# 为什么要使用模拟框架?,c#,.net,mocking,moq,rhino-mocks,C#,.net,Mocking,Moq,Rhino Mocks,我们目前正在使用Autofac作为IoC容器来遵循DI模型 我们最近开始研究MOQ和rhinomock等模拟框架。然而,我们似乎无法证明它们的使用比为每个接口创建模拟实现类更合理 为什么会这样: var mock = new Mock<IFoo>(); mock.Setup(foo => foo.DoSomething("ping")).Returns(true); 后者更详细,但似乎更灵活,更适合复杂的模拟 然而,我们似乎无法证明这一点 它们的用法超过了仅仅创建Mock 我

我们目前正在使用Autofac作为IoC容器来遵循DI模型

我们最近开始研究MOQ和rhinomock等模拟框架。然而,我们似乎无法证明它们的使用比为每个接口创建模拟实现类更合理

为什么会这样:

var mock = new Mock<IFoo>();
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);
后者更详细,但似乎更灵活,更适合复杂的模拟

然而,我们似乎无法证明这一点 它们的用法超过了仅仅创建Mock 我们的每个应用程序的实现类 接口

这正是模拟框架可以让您避免做的事情——创建存根或模拟实现只是为了能够测试类的行为


不管怎么说,你所做的都没有错,如果你的项目可行的话,一定要坚持下去——对许多人来说,这似乎是一项非常平凡的任务,而这正是使用模拟框架可以节省大量时间的地方,此外,还应避免仅仅为了测试而导致代码库膨胀,以及在模拟实现中出现额外错误的可能性。

您在示例中展示的更多是假的/存根,而不是真正的模拟。确实,如果您只想从依赖对象预录制行为,那么通常假行为可能是比使用假行为更好的选择模拟框架

马丁·福勒(Martin Fowler)的一篇经典文章讨论了这一事实,我从中摘取了以下段落:

这里的关键区别在于我们如何 验证订单是否正确 在它与 仓库。通过国家核查,我们 这样做是通过对 仓库的状态。模拟使用行为 验证,而不是检查 查看订单是否正确 拜访仓库

基本上,对于mock,您通常打算检查测试中的方法是如何作用于依赖项的——您的mock有期望值,并且在方法运行后验证这些期望值

当然,您仍然可以编写自己的逐案模拟,但使用框架将节省大量时间,提供更具可读性的测试,并节省测试中的错误

这一点尤其正确,因为您的期望变得越来越复杂,想象一下有一个方法来测试,该方法调用特定的依赖类的次数可变,并且根据输入参数的不同,调用不同的值-这对于您自己编写一个模拟是复杂的,但是使用一个好的模拟框架是微不足道的

为了用一些代码进行演示,想象一下这个PrintOrders方法(请原谅这个愚蠢的例子):

public void PrintForeignOrders(列出订单)
{
foreach(订单中的var订单)
{
if(order.IsForeign)
{
printer.PrintOrder(订单号、订单名);
}
}
}
您可能至少需要测试:

  • 当列表为空时,不会打印任何内容
  • 当有国外订单时,它会被打印出来
  • 当有两个订单时,两个订单都会打印(使用正确的编号和名称)

有了一个好的模拟框架,针对注入的打印机对象设置这些测试只需几下键盘。

每次更改界面时,都必须调整每个手动编码的模拟对象(实际上是存根),以符合新界面


因此,拥有大量手工编码的存根对象将导致在每次更改接口时对测试代码进行大量维护。但是,由模拟框架创建的模拟将始终与更新的界面兼容。

这里有一个类似的问题,可以提供一些见解:@Jason Down:我想说这不是一个“类似”的问题,而是同一个问题。投票以重复方式关闭。@堂·罗比:是的,我想这几乎是完全相同的问题。我一直觉得使用DI解析模拟对象比直接新建模拟对象要好,因为模拟对象可能也有依赖项,如果只使用模拟,就必须手动设置,但可以通过DI框架自动连接。
class FooMock : IFoo {
  bool DoSomething(string input) {
    return input == "ping";
  }
}
mock = new FooMock();
public void PrintForeignOrders(List<Orders> orders)
{
    foreach(var order in orders)
    {
        if (order.IsForeign)
        {
            printer.PrintOrder(order.Number, order.Name);
        }
    }
}