Answers:
您的问题是关于MS Fakes框架与NMock有何不同,看来其他答案已经解决了其中的一些问题,但是这里有一些有关它们如何相同和如何不同的更多信息。NMock也类似于RhinoMocks和Moq,因此我将它们与NMock分组在一起。
我立即看到NMock / RhinoMocks / Moq与MS Fakes框架之间存在3个主要差异:
MS伪造框架使用生成的代码,就像在Visual Studio早期版本中的Accessors一样,而不是通用类型。当您要使用伪造的框架作为依赖项时,可以将包含依赖项的程序集添加到测试项目的引用中,然后右键单击它以生成测试双精度(残桩或垫片)。然后,当您进行测试时,实际上是在使用这些生成的类。NMock使用泛型来完成同一件事(即IStudentRepository studentRepository = mocks.NewMock<IStudentRepository>()
)。我认为,MS Fakes框架方法禁止在测试中进行代码导航和重构,因为您实际上是在针对生成的类而不是实际界面进行操作。
MS伪造框架提供存根和痣(垫片),而NMock,RhinoMocks和Moq都提供存根和模拟物。我真的不理解MS决定不包含模拟游戏的决定,而且我个人出于以下原因不喜欢黑痣。
使用MS Fake框架,您可以提供要存根的方法的替代实现。在这些替代实现中,您可以指定返回值并跟踪有关如何或是否调用该方法的信息。使用NMock,RhinoMocks和Moq,您可以生成一个模拟对象,然后使用该对象指定存根返回值或跟踪交互(是否以及如何调用方法)。我发现MS的伪造方法更加复杂且表达能力较差。
为了澄清框架提供的差异:NMock,RhinoMocks和Moq都提供两种类型的测试双打(存根和模拟)。伪造品框架提供存根和痣(它们称它们为垫片),但不幸的是不包含模拟。为了了解NMock和MS Fakes之间的区别和相似之处,了解以下几种不同的测试重复类型是有帮助的:
存根(Stub):当您需要提供方法或属性的值时,将使用存根( Stub),该值将由被测方法要求测试倍数。例如,当我的被测试方法调用IStudentRepository测试double的DidSStudentExist()方法时,我希望它返回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”示例中,您为DosStudentExist方法创建了一个全新的实现(请注意,它被称为“ DoesStudentExistInt32”,因为在其生成存根对象时,fakes框架会将参数数据类型附加到方法名称中,我认为这使测试)。老实说,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)的示例更具表现力。
les鼠:说实话,我不喜欢mole鼠,因为它们有可能被滥用。我非常喜欢单元测试(尤其是TDD)的一件事是,测试代码可以帮助您了解编写不良代码的位置。这是因为测试写得不好的代码很困难。使用摩尔时,情况并非如此,因为摩尔实际上是设计用来允许您针对未注入的依赖项进行测试或测试私有方法。它们的工作方式与存根类似,不同的是您使用ShimsContext这样:
using (ShimsContext.Create())
{
System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}
我对垫片的担心是,人们会开始将它们视为“一种更简单的单元测试方法”,因为它不会强迫您按照应有的方式编写代码。有关此概念的更完整文章,请参阅我的这篇文章:
有关与伪造框架有关的某些问题的更多信息,请查看以下文章:
如果您有兴趣学习RhinoMocks,请观看以下Pluralsight培训视频(完整披露-我编写了本课程,并获得了稿酬,以获取观点,但我认为它适用于本次讨论,因此在此进行了介绍):
您是正确的,但故事还有很多。要摆脱此答案,最重要的事情是:
您的架构应适当使用存根和依赖项注入,而不是依赖Fakes和嘲笑的拐杖
伪造和模拟对测试不应更改的代码非常有用,例如:
Shims(在开发过程中被称为“ Moles”)确实是通过绕行调用而运行的模拟框架。填充程序无需费力地构建模拟程序(是的,即使使用Moq也比较麻烦!),而是简单地使用已经存在的生产代码对象。Shims只需将呼叫从生产目标重新路由到测试代表。
存根是从目标项目中的接口生成的。Stub对象就是接口的实现。使用Stub类型的好处是,您可以快速生成一个Stub,而不会因许多一次性使用Stub造成测试项目混乱,更不用说浪费时间创建它们了。当然,您仍然应该创建具体的存根,以便在许多测试中使用。
有效地实现伪造(Shims,Mocks和Stub类型)需要一点时间来适应,但值得付出努力。通过使用Shims / Mole,Mocks和Stub类型,我个人节省了数周的开发时间。希望您能像我一样享受这项技术带来的乐趣!
据我了解,Visual Studio团队希望避免与.NET可用的各种模拟库竞争。MS经常会面临这样艰难的决定。如果他们不提供某些功能(“为什么MS不向我们提供模拟库;模拟是这么普遍的要求?”),那么就被谴责,如果不这样做(“为什么Microsoft如此积极地采取行动并推动它的发展,为什么?天生支持者退出市场?”)很多时候(但并非总是如此),他们决定阻止仅仅提供自己的替代方案来替代现有和广受欢迎的技术。这里似乎就是这种情况。
伪造的伪装功能确实非常有用。当然,有危险。需要一定的纪律以确保仅在必要时使用此功能。但是,它填补了很大的空白。我的主要抱怨是,它仅随VS 2012 Ultimate版一起提供,因此仅适用于.NET开发社区的一个子部分。太遗憾了。
伪造包括两种不同的“伪造”对象。第一个称为“存根”,本质上是一个自动生成的虚拟对象,其默认行为可以(并且通常会)被覆盖以使其更有趣。但是,它确实缺少大多数当前可用的模拟框架提供的某些功能。例如,如果要检查存根实例上的方法是否已调用,则需要自己添加逻辑。基本上,如果您现在手动编写自己的模拟,存根可能看起来是一种改进。但是,如果您已经在使用功能更全的模拟框架,则可能会感觉Fakes存根中缺少一些重要的部分。
Fakes提供的另一类对象称为“填充程序”,它公开了一种机制,用于替换尚未(或无法)解耦的依赖项行为,以通过模拟进行标准替换。AFAIK,TypeMock是当前提供此类功能的唯一主要模拟框架之一。
顺便说一句,如果您以前尝试过Moles,那么Fakes本质上是一回事,最终从Microsoft Research进入了实际产品。
关于假(Shim + Stub)对象,上面已经对其进行了很好的定义,尽管我想最后一条评论中的最后一段很好地总结了整个情况。
尽管很多人会认为伪(Shim + Stub)对象是某些单元测试用例中的好资产,但缺点是,无论您使用的是Visual Studio 2012还是Visual Studio 2013,这些选项都仅可用具有Premium或Ultimate版本。IOW,这意味着您将不会在任何Pro版本上运行任何这些假货(Shim + Stub)。
您可能会在Pro版本上看到Fakes(Shim + Stub)菜单选项,但是请注意,很有可能您最终将一无所有...它不会产生任何编译错误,告诉您一些重要信息缺少,选项不存在,所以不要浪费时间...
这是在开发团队中考虑的重要因素,特别是如果一个人是唯一使用Ultimate版本的人,而其他人都使用Pro版本...另一方面,无论您使用哪个Visual Studio版本,都可以通过Nuget轻松安装Moq。我使用Moq没问题,任何工具的关键是要知道它们的用途以及如何正确使用它们;)