模拟框架与MS Fakes框架

时间:2012-03-13 02:08:04

标签: unit-testing microsoft-fakes

对NMock与VS 2011 Fakes Framework等模拟框架的差异感到有些困惑。 通过MSDN,我理解的是Fakes允许你像RhinoMock或NMock一样模拟你的依赖,但是方法不同,Fakes生成代码来实现这个功能,但Mocks框架没有。那么我的理解是正确的吗?假货只是另一个模拟框架

5 个答案:

答案 0 :(得分:176)

你的问题是关于MS Fakes框架与NMock的不同之处,似乎其他答案已经解决了其中一些问题,但这里有一些关于它们是如何相同以及它们如何不同的更多信息。 NMock也类似于RhinoMocks和Moq,因此我将它们与NMock分组。

我在NMock / RhinoMocks / Moq与MS Fakes Framework之间看到了3个主要差异:

  • MS fakes框架使用生成的代码,非常类似于Visual Studio的早期版本中的Accessors而不是泛型类型。如果要将fakes框架用于依赖项,则将包含依赖项的程序集添加到测试项目的引用中,然后右键单击它以生成测试双精度程序(存根或填充程序)。然后,当您进行测试时,实际上您正在使用这些生成的类。 NMock使用泛型来完成同样的事情(即IStudentRepository studentRepository = mocks.NewMock<IStudentRepository>())。在我看来,MS Fakes框架方法禁止在测试中进行代码导航和重构,因为你实际上是在对生成的类进行操作,而不是真正的接口。

  • MS fakes框架提供存根和痣(垫片),而NMock,RhinoMocks和Moq都提供存根和模拟。我真的不明白MS决定不包括嘲讽,我个人不是鼹鼠的粉丝,原因如下所述。

  • 使用MS fakes框架,您可以提供要存根的方法的替代实现。在这些备用实现中,您可以指定返回值并跟踪有关如何或是否调用方法的信息。使用NMock,RhinoMocks和Moq,您可以生成一个模拟对象,然后使用该对象指定存根返回值或跟踪交互(是否以及如何调用方法)。我发现MS伪造的方法更复杂,更不具有表现力。

澄清框架提供的不同之处:NMock,RhinoMocks和Moq都提供两种类型的测试双打(存根和模拟)。假货框架提供存根和痣(他们称之为垫片),遗憾的是不包括模拟。为了理解NMock和MS Fakes之间的差异和相似之处,了解这些不同类型的测试双精度是有帮助的:

存根:当您需要提供方法或属性的值时,将使用存根,这些方法或属性将通过测试方法询问您的测试双倍。例如,当我的测试方法调用IStudentRepository测试的DoesStudentExist()方法时,我希望它返回true。

NMock和MS假货中存根的想法是一样的,但是对于NMock,你会做这样的事情:

Stub.On(mockStudentRepository).Method("DoesStudentExist").Will(Return.Value(true));

使用MSFakes,你会做这样的事情:

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() // Generated by Fakes.
{
    DoesStudentExistInt32 = (studentId) => { return new Student(); }
};

注意在MS Fakes示例中,您为DoesStudentExist方法创建了一个全新的实现(请注意,它被称为DoesStudentExistInt32,因为伪造框架在生成存根对象时将参数数据类型附加到方法名称,我认为这会模糊不清测试的清晰度)。说实话,NMock实现也会让我感到困惑,因为它使用字符串来标识方法名称。 (请原谅我,如果我误解了如何使用NMock。)这种方法确实会抑制重构,因此我强烈建议使用RhinoMocks或Moq而不是NMock。

模拟:模拟用于验证测试方法与其依赖项之间的交互。使用NMock,您可以通过设置类似于此的预期来实现此目的:

Expect.Once.On(mockStudentRepository).Method("Find").With(123);

这是我更喜欢RhinoMocks和Moq而不是NMock的另一个原因,NMock使用较旧的期望风格,而RhinoMocks和Moq都支持Arrange / Act / Assert方法,在此方法中您将预期的交互指定为最后的断言像这样的测试:

stubStudentRepository.AssertWasCalled( x => x.Find(123));

再次注意,RhinoMocks使用lambda而不是字符串来标识方法。 ms fakes框架根本不提供模拟。这意味着在您的存根实现(请参阅上面的存根的描述)中,您必须设置稍后验证的变量已正确设置。这看起来像这样:

bool wasFindCalled = false;

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() 
{
    DoesStudentExistInt32 = (studentId) => 
        { 
            wasFindCalled = true;
            return new Student(); 
        }
};

classUnderTest.MethodUnderTest();

Assert.IsTrue(wasFindCalled);

我发现这种方法有点复杂,因为你必须在存根中跟踪调用,然后在测试中断言它。我发现NMock,特别是RhinoMocks的例子更具表现力。

鼹鼠(垫片):坦率地说,我不喜欢鼹鼠,因为它们有可能被误用。我非常喜欢单元测试(特别是TDD)的一个方面是测试代码可以帮助您了解编写代码不佳的地方。这是因为测试编写糟糕的代码很困难。使用moles时不是这样,因为moles实际上是为了测试未注入的依赖项或测试私有方法而设计的。它们的工作方式类似于存根,除了你使用像这样的ShimsContext:

using (ShimsContext.Create())
{
    System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}

我对垫片的担心是人们会开始将它们视为&#34;一种更简单的单元测试方式&#34;因为它并没有强迫你以你应该的方式编写代码。有关此概念的更完整的文章,请参阅我的这篇文章:

有关假货框架相关问题的更多信息,请查看以下帖子:

如果你有兴趣在这里学习RhinoMocks,那就是Pluralsight培训视频(完全披露 - 我写了这门课程并获得了观点的版税,但我认为它适用于这个讨论,所以我&m; m包括在这里):

答案 1 :(得分:23)

你是对的,但故事还有更多。从这个答案中取消的最重要的事情是:

  1. 您的架构应该正确使用存根和依赖注入,而不是依赖于伪造和嘲笑的拐杖

  2. 假货和模拟对于测试您不应该或不能更改的代码非常有用,例如:

    • 未使用(或有效使用)存根的旧版代码
    • 第三方API
    • 您没有源代码的资源
  3. 垫片(在开发过程中称为“Moles”)确实是一种通过绕道调用来操作的模拟框架。而不是精心构建模拟(是的,即使使用Moq也相对痛苦!),垫片只需使用已经存在的生产代码对象。垫片只是将调用从生产目标重新路由到测试代理。

    Stubs 是从目标项目中的接口生成的。 Stub对象就是 - 接口的一个实现。使用Stub类型的好处是,您可以使用许多一次性使用存根快速生成存根而不会混乱您的测试项目,更不用说浪费时间创建它们了。当然,您仍然应该创建具体的存根,以便在许多测试中使用。

    有效地实施Fakes(Shims,Mocks和Stub类型)需要一点点习惯,但值得付出努力。通过使用Shims / Mole,Mocks和Stub类型,我个人节省了数周的开发时间。我希望你能拥有与我一样多的乐趣!

答案 2 :(得分:15)

据我了解,Visual Studio团队希望避免与.NET可用的各种模拟库竞争。 MS经常面临这样的艰难决定。如果他们没有提供某些功能(“为什么MS没有为我们提供模拟库;模拟是如此常见的要求?”)并且如果他们这样做(“为什么微软如此积极地行动并推动其自然支持者退出市场?“)很多时候,但并非总是如此,他们决定不再仅仅提供自己的替代品来获得可用和广受欢迎的技术。这似乎就是这种情况。

Fakes的垫片功能真的很有用。当然,有危险。确保您只在必要时使用它需要一些纪律。然而,它填补了一个很大的差距。我的主要抱怨是它仅与VS 2012的Ultimate版本一起提供,因此只能用于.NET开发社区的子部分。太遗憾了。

答案 3 :(得分:13)

假货包括两种不同的“假”对象。第一个称为“存根”,实际上是一个自动生成的虚拟对象,其默认行为可以(并且通常会)被覆盖以使其成为更有趣的模拟。但是,它确实缺少大多数当前可用的模拟框架提供的一些功能。例如,如果要检查是否调用了存根实例上的方法,则需要自己添加逻辑。基本上,如果您现在手动编写自己的模拟,存根可能看起来像是一种改进。但是,如果您已经使用了功能更全面的模拟框架,您可能会觉得Fakes存根中缺少一些重要的部分。

Fakes提供的另一类对象称为“垫片”,它揭示了一种机制,用于替换尚未(或不能)通过模拟替换标准替换的依赖关系的行为。 AFAIK,TypeMock是目前提供此类功能的唯一主要模拟框架。

顺便说一下,如果你之前尝试过Moles,那么Fakes基本上就是一样的东西,最终会从微软研究院出来并成为一个真正的产品。

答案 4 :(得分:1)

关于假(Shim + Stub)对象,它已在上面定义得很好,但我猜最后一篇评论的最后一段很好地总结了整个情况。

虽然很多人会争辩说Fake(Shim + Stub)对象是某些单元测试案例中的好资产,但缺点是无论你是使用Visual Studio 2012还是Visual Studio 2013,这些选项都是如此仅适用于Premium或Ultimate版本。 IOW,这意味着你不会在任何专业版上运行任何伪造品(Shim + Stub)。

您可能会在Pro版本上看到Fakes(Shim + Stub)菜单选项,但要注意,有一些非常强大的机会,你最终将无所事事......它不会产生任何编译错误告诉你缺少重要的东西,选项就不存在,所以不要浪费你的时间......

这是在开发团队中考虑的一个重要因素,特别是如果一个是唯一一个使用Ultimate版本而其他人都使用Pro版本...另一方面Moq可以通过Nuget轻松安装,无论哪个Visual Studio版本你用。我使用Moq没有问题,任何工具的关键是知道它们的用途以及如何正确使用它们;)