Rhino Mocks上的模拟和存根之间有什么区别?


149

我对此玩的还不够,通常使用模拟,但是我想知道两者之间的区别以及何时在Rhino Mocks上使用一个或另一个。

更新:

我也用Ayende的话找到了我问题的答案:

存根和模拟的区别

您可以在本文中获得以下术语的实际定义:Mocks Are n't Stubs。我想从Rhino Mocks的角度着眼于差异。

模拟是可以设置期望值的对象,它将验证期望的动作确实已经发生。存根是您用来传递给被测代码的对象。您可以对它设置期望,以便它以某些方式起作用,但是这些期望永远不会得到验证。存根的属性将自动表现为正常属性,并且您无法对它们设置期望。

如果要验证被测代码的行为,将使用具有适当期望值的模拟并进行验证。如果您只想传递可能需要以某种方式起作用但不是测试重点的值,则可以使用存根。

重要说明:存根永远不会导致测试失败。


Answers:


148

按照这个

...简单地说,Mock和Stub对象之间是有区别的,RhinoMocks认识到允许我们编写更好地说明其目的的测试。

模拟对象用于定义期望,即:在这种情况下,我希望使用此类参数调用方法A()。嘲讽记录并验证这种期望。

另一方面,存根具有不同的目的:它们不记录或验证期望,而是允许我们“替换”“假”对象的行为,状态以利用测试场景...


我发现这呼应了同样的消息,作为这个问题的答案接受另一个有用的帖子- martinfowler.com/articles/mocksArentStubs.html
singh1469

20

一般来说,单元测试会调用函数和方法,然后检查是否发生了预期的行为。这些功能和方法可能需要参数。我们使用存根和模拟来满足这些参数。有时我们可能还会模拟全局对象。

存根

存根是一个很小的假对象,您的测试可以将其用作参数来使函数调用起作用。这使我们可以验证被测函数的行为。它不允许我们验证任何副作用,因为存根没有实现。

cks

模拟是具有实现的存根。如果我们的测试功能与我们的模拟对象进行了交互,我们可以验证该模拟是否已经按照我们的预期进行了交互。

例如,假设我们有一个模拟的User对象,并且我们想验证session.login方法是否有效,我们可能要检查是否设置了user.lastLoggedIn。我们可以创建一个模拟用户来实现此方法。当我们调用session.login时,我们可以断言user.lastLoggedIn具有我们期望的状态。

总结一下

模拟是具有实现的存根,这使我们可以测试副作用。

区别仍然重要吗?

就像明喻和隐喻之间的差异一样,存根和模拟之间的差异是微妙的和历史的,也许与测试领域中的不同社区和哲学有更多的关系,而不是任何主要的技术差异。

它们表示测试的方法略有不同。模拟可以像存根一样编写。存根通常可以扩展为模拟。

您应该使用哪个?

您可能会发现自己开始创建存根,然后您可能会发现需要为某些对象创建完整的模拟。您可能想随便模拟所有内容,或者只想在需要的地方模拟。


7

Mock和stub之间的区别:使用stub,您可以修复单元测试的输入:因此,您的单元测试不会通过重写某些方法的实现来纠正stub和Stub上的断言,从而修复假对象的行为。使用Mock,您可以修复单元测试的输出:因此,单元测试可以通过检查模拟对象中的内部交互来对Mocking对象做出期望。


您似乎在说测试应该“检查”模拟的输出。如果这是您的意思,那是不正确的。模拟不应该被测试;它在那里,因此您可以测试其他代码。还是您的最后一句话是其他意思?
Andrew Barber 2012年

1
嗨,安德鲁,正如我用Mock编写的那样,您可以固定测试的输出,以免进行测试。否则,我写了Mock允许您检查交互性(预期行为... ;-)
Hassan Boutougha

1
好的,这更有意义。感谢您的澄清!
安德鲁·巴伯

>不对存根进行断言为什么在许多断言库中仍然存在should have been called with用于断言stub参数的方法。
hellboy


0

我也注意到的一件事是,当我使用MockRepository.GenerateMock时,我需要在特定方法调用上明确设置期望值以拦截该调用。使用存根,只要它是虚拟的,它似乎就会自动拦截任何方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.