对于Mock框架(例如NMock)与VS 2011 Fakes框架的区别有些困惑。
通过MSDN,我了解到Fakes允许您像RhinoMock或NMock一样模拟依赖项,但是方法不同,Fakes生成代码以实现此功能,而Mocks框架则没有。我的理解正确吗?是假货只是另一个Mock框架
最佳答案
您的问题是关于MS Fakes框架与NMock有何不同,看来其他答案已经解决了其中的一些问题,但是这里有一些有关它们如何相同和如何不同的更多信息。 NMock也类似于RhinoMocks和Moq,因此我将它们与NMock分组在一起。
我立即看到NMock / RhinoMocks / Moq与MS Fakes框架之间存在3个主要差异:
IStudentRepository studentRepository = mocks.NewMock<IStudentRepository>()
)。我认为,MS Fakes框架方法禁止在测试中进行代码导航和重构,因为您实际上是在针对生成的类而不是实际界面进行操作。 为了澄清框架提供的差异:NMock,RhinoMocks和Moq都提供两种类型的测试双打(存根和模拟)。伪造品框架提供存根和痣(它们称它们为垫片),但不幸的是不包含模拟。为了了解NMock和MS Fakes之间的区别和相似之处,有助于理解这些不同类型的测试重复是什么:
存根:存根在需要提供方法或属性的值时使用,该值将由被测方法要求您的测试加倍。例如,当我的被测试方法调用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。
Mocks: Mocks用于验证被测方法及其依赖项之间的交互。使用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)的示例更具表现力。
痣(Shims):坦率地说,我不喜欢痣,因为它们可能被滥用。我非常喜欢单元测试(尤其是TDD)的一件事是,测试代码可以帮助您了解编写不良代码的位置。这是因为测试写得不好的代码很困难。使用摩尔时,情况并非如此,因为摩尔实际上是设计用来允许您针对未注入(inject)的依赖项进行测试或测试私有(private)方法。它们的工作方式与存根类似,不同的是您使用ShimsContext这样:
using (ShimsContext.Create())
{
System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}
我对垫片的担心是,人们会开始将它们视为“一种更简单的单元测试方法”,因为它不会强制您按照应有的方式编写代码。有关此概念的更完整文章,请参阅我的这篇文章:
有关与伪造框架有关的某些问题的更多信息,请查看以下文章:
如果您有兴趣学习RhinoMocks,请观看以下Pluralsight培训视频(完整披露-我编写了本类(class),并获得了稿酬,以获取观点,但我认为它适用于本次讨论,因此在此进行了介绍):
关于unit-testing - 模拟框架与MS Fakes框架,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9677445/