RhinoMock、TypeMock、NUnit的Mocking有何区别?

19

我刚开始进行测试驱动开发,想知道RhinoMock、TypeMock和NUnit内置的模拟的主要区别?

非常感谢任何信息!

4个回答

37

TypeMock是一款商业产品(意味着你需要为它付费),但它可以模拟具体对象,而不像RhinoMocks/NUnit/MoQ只能模拟接口/抽象类。它是如何实现的边界黑魔法,但它在CLR上做了一些非常聪明的事情。

当你在项目中使用不太多用接口的库时,这特别有用。例如,你可以使用TypeMock来模拟一个LINQtoSQL数据上下文或Sharepoint对象。但是,如果你在使用TypeMock时仍然应该注意好的应用程序设计。

据我所知,除了少量语法差异外,大多数模拟框架已经摒弃了旧的记录/回放模式。通常,你可以通过编写期望的流畅接口来设置模拟。

个人而言,我只使用过MoQ并且非常喜欢它。


2
静态和密封类并不总是一种糟糕的设计,但使用RhinoMocks/NUnit/MoQ无法模拟它们。你会因为工具不支持而放弃整个功能集吗? - Egor Pavlikhin
@HeavyWave 他们并不总是糟糕的设计,但如果你发现自己处于想要/需要模拟它们的情况下,那么这可能是一次糟糕的设计。 - Kirschstein
2
啊,不行。我有很多课程是不应该被用户扩展的,所以它们不是虚拟/密封的。而且你猜怎么着 - 我经常需要模拟其中一个类来进行一项需要显示该类特定行为的小测试。解除密封并不好 - 框架“依赖”于它们不能被扩展。 - TomTom
@TomTom - 这样做可能不太好看,但我们可以在这些类的声明周围放置编译条件,以允许进行单元测试的构建不包含封闭类,并创建具有封闭类的构建。 - jpierson
1
@jpierson 是的,这完全违背了单元测试的精神,甚至一点都不好笑 ;) - TomTom
好消息是,基本的TypeMock产品现在是免费的。 - AssafR

19
一段名为TDD-理解Mock对象的视频,由Roy Osherove主讲,对学习不同Mock库之间的区别非常有帮助。他没有过多详细地介绍每个方面,但足以让您理解。希望这可以帮到您。Roy也是TypeMock的首席架构师,在单元测试领域非常有影响力。我强烈推荐这个视频,特别是想学习如何使用mocking并了解可用库的人。
TypeMock和开源库之间的主要区别在于,TypeMock使用Microsoft提供的Profiler API而不是动态代理。这使得TypeMock可以模拟具体类和静态方法。如果您不确定分析器是什么,请注意,JetBrain的dotTrace和RedGate的Ants.Net分析器等工具使用的是相同的API。TypeMock只是以一种不同的方式使用API来虚假(mock)您告诉它的内容。
@RichardOD,感谢提醒,他的书 "The Art of Unit Testing" 在视频中没有详细介绍的地方有更深入的阐述。我拥有这本书,它非常有启发性。

他还有一本很棒的书。 - RichardOD

14
Rhino.Mocks是一个开源、不断发展和改进的框架,由业界最多产的开发者之一开发。它已经存在一段时间,因此支持相当多的不同模拟方法。学习可能有点困难,因为你可能会找到一些旧的做事方式的教程。这里有个提示:SetUpResultFor()和Expect.Call()是旧的做法。新的方法是mockObject.AssertWasCalled()。
我没有亲身体验过以下内容,但...
MOQ是一个开源、不断发展和改进的框架,由业界某些不太多产的开发者(与Ayende相比)开发。它较新,因此缺少Rhino.Mocks具有的某些功能。通常这不是问题,因为这些特性往往是Rhino中有些废弃的特性。我听说因为这个原因,它稍微容易学一些(模拟框架学习起来并不难)。
NUnit Mocks作为一种模拟框架非常古老。 它不支持当前首选的安排-行动-断言语法,而是依赖于Expect-Verify(录制/回放)。 它还依赖于字符串来标识方法和属性名称,而不是lambda表达式。 这使得它在重构方面更加耐用。 这是一个严重的问题。 我不建议使用它。
TypeMock Isolater是一种来自Roy Osherove(或其所有的公司)的高级付费模拟框架,他知道如何进行测试,但对如何应用测试有一些略微有争议的意见。从能做到的事情来看,它真的很强大——深入到低层次并修改CLR对象的工作方式。 然而TypeMock背后的哲学并不完全符合TDD。 TDD的一个好处是通过接受模拟框架的限制,您将设计出更好的代码。 TypeMock会打破这些限制。据我所知,它主要被那些试图测试无法控制的代码的人使用。

2
这个踩的不是我,但我确实不同意“拥抱Mocking框架的限制,你会设计出更好的代码”的说法。我的意思是,你认真的吗?比如我想遵循“信息隐藏”原则并完全封装一个非公共的帮助类,那些有限的Mocking工具就不允许我这样做!暴露那个帮助类并减少封装怎么会导致更好的代码呢? - Rogério
1
我并不是说像TypeMock这样的巨无霸没有其存在的意义。我是说,如果你对自己的代码有完全的控制,并遵循良好的实践,你将不需要任何高级的Mocking功能。证据呢?在Jermey Miller、Rob Connery、Scott Bellware等强大的开发者中,我从未听说过他们使用除Rhino和MoQ之外的任何东西。而Ayende是个聪明人(可能是最聪明的人)——如果他觉得他需要模拟静态内容,他会这么做的。至于DI是一个主要原则——它是SOLID中的D! - George Mauer
1
我阅读了所有这些文章,我确实理解它们。你关于DI、服务定位器和插件被用于DIP是正确的;我从未说过相反的话。但是,正如我之前所解释的那样,这些概念是不同的。Bob Martin创造了DIP,但并非DI,DI一词是由Martin Fowler在http://martinfowler.com/articles/injection.html中创造的。Martin错误地认为DIP对OO的重要性。这不仅仅是我的观点,还有其他著名作者关于OO的书籍和文章中都没有提到DIP,例如Fowler、Josh Bloch、GoF、Andrew Hunt、Steve McConnel、Brian Kernighan等人。 - Rogério
2
关于Ayende没有问题,我只是好奇。我很高兴看到你不会盲目跟随别人。但是你应该更加开放地看待模拟工具限制的后果。 当开发人员仅为了进行单元测试而创建单独的接口或声明方法为虚拟方法时,他正在给项目带来损害,增加了不必要的、毫无意义的复杂性。一个好的模拟工具不应该强制这样做。试图“强迫”开发人员遵循良好的面向对象编程原则根本行不通,因为那些不好的开发人员总会绕过它。 - Rogério
2
哇,一个以文明方式结束的互联网争论?看看天空!这是世界末日吗?我会在另一个帖子上跟进,但我有一个好奇的问题。TDD的过程也对开发施加了一定的限制。我认为这些限制是关于TDD的事情之一,可以帮助人们学习如何创建良好的设计。你同意吗?如果是这样,那么你同意限制可以帮助人们学习 - 你只是认为Rhino Mocks施加的限制是错误的吗? - George Mauer
显示剩余14条评论

2
我经常使用TypeMock,发现它是一个非常强大的工具,可以提高我的单元测试覆盖率。这是因为我使用SharePoint,并且只有TypeMock可以允许我模拟SharePoint类 - 因为它们是具体类而不是接口。
使用RhinoMock、Moq、NUnit等无法模拟SharePoint类,因为(我认为)它们需要接口来模拟对象,而不能模拟实际的具体类。
如果您的代码确实使用了许多接口,并且不需要模拟具体类,则TypeMock有点昂贵,但对于您获得的功能,它是值得的。

3
你可以编写一个简单的包装类来封装SharePoint类,并将调用转发到原始类。这个包装类可以通过接口访问,并且可以进行模拟。包装类还可以充当门面,简化与第三方类的交互。在此情况下,你不需要使用TypeMock。 - Wim Coenen
10
现实情况检验:时间就是金钱。是的,我可以再写100个类来解决某个工具的限制问题。我也可以使用一个工具。更便宜,代码更少。 - TomTom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接