我读过各种关于测试中模仿和存根的文章,包括Martin Fowler的《Mocks Aren't Stubs》,但我仍然不理解其中的区别。


当前回答

使用一个心智模型确实帮助我理解了这一点,而不是所有的解释和文章,这些都不能“理解”。

想象一下,你的孩子桌子上有一个玻璃盘子,他开始玩它。现在,你害怕它会破裂。所以,你给了他一个塑料盘子。这将是一个Mock(相同的行为,相同的接口,“更软的”实现)。

现在,假设你没有塑料替代品,所以你解释说“如果你继续玩它,它会碎的!”这是一个Stub,您预先提供了一个预定义的状态。

哑巴就是他根本不用的叉子…间谍可能是提供你已经使用过的有效解释。

其他回答

下面是对每一个的描述,然后是真实世界的样本。

Dummy - just bogus values to satisfy the API. Example: If you're testing a method of a class which requires many mandatory parameters in a constructor which have no effect on your test, then you may create dummy objects for the purpose of creating new instances of a class. Fake - create a test implementation of a class which may have a dependency on some external infrastructure. (It's good practice that your unit test does NOT actually interact with external infrastructure.) Example: Create fake implementation for accessing a database, replace it with in-memory collection. Stub - override methods to return hard-coded values, also referred to as state-based. Example: Your test class depends on a method Calculate() taking 5 minutes to complete. Rather than wait for 5 minutes you can replace its real implementation with stub that returns hard-coded values; taking only a small fraction of the time. Mock - very similar to Stub but interaction-based rather than state-based. This means you don't expect from Mock to return some value, but to assume that specific order of method calls are made. Example: You're testing a user registration class. After calling Save, it should call SendConfirmationEmail.

存根和Mock实际上是Mock的子类型,两者都交换了实际实现和测试实现,但出于不同的、特定的原因。

存根是为测试目的而构建的伪对象。mock是记录预期调用是否有效发生的存根。

从论文模拟角色,而不是对象,由jMock的开发人员:

存根是返回罐装的产品代码的虚拟实现 结果。Mock对象充当存根,但也包括到的断言 测量目标对象与其邻居的交互作用。

所以,主要的区别是:

在存根上设置的期望通常是通用的,而在mock上设置的期望可能更“聪明”(例如,在第一次调用时返回this,在第二次调用时返回this等)。 存根主要用于设置SUT的间接输入,而mock可用于测试SUT的间接输入和间接输出。

综上所述,同时也试图驱散福勒文章标题中的困惑:mock是存根,但它们不仅仅是存根。

加上有用的答案,其中最强大的一点使用模拟比潜艇

如果合作者(主代码所依赖的合作者)不在我们的控制之下(例如来自第三方库), 在这种情况下,stub比mock更难编写。

存根是一个空函数,用于在测试期间避免未处理的异常:

function foo(){}

mock是一个人为的函数,用于避免在测试期间对操作系统、环境或硬件的依赖:

function foo(bar){ window = this; return window.toString(bar); }

在断言和状态方面:

在事件或状态更改之前断言模拟 存根不被断言,它们在事件之前提供状态,以避免执行来自不相关单元的代码 间谍就像存根一样被设置,然后在事件或状态改变后被断言 假的是不断言的,他们运行后的事件硬编码的依赖,以避免状态

参考文献

极客词汇:Mock 极客词汇:存根 极客术语:间谍 测试替身:假的,模拟和存根