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


当前回答

存根是向SUT返回值的测试double。

模拟是测试用于验证SUT正确调用依赖项的双重测试。

而且,mock通常是存根

其他回答

关于这个问题,我认为Roy Osherove在他的书《单元测试的艺术》(85页)中给出了最简单、最清晰的答案。

判断我们正在处理存根的最简单方法是注意到存根永远不会通过测试。测试使用的断言总是反对的 被测试的班级。 另一方面,测试将使用一个模拟对象来验证 测试是否失败。[…] 同样,模拟对象是我们用来检查测试是否失败的对象。

Stub和mock都是假的。

如果您对假的进行断言,这意味着您将假的用作mock,如果您仅使用假的运行测试而没有对其进行断言,那么您将假的用作存根。

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

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的子类型,两者都交换了实际实现和测试实现,但出于不同的、特定的原因。

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

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

所以,主要的区别是:

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

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

存根是向SUT返回值的测试double。

模拟是测试用于验证SUT正确调用依赖项的双重测试。

而且,mock通常是存根

Stub是实现组件接口的对象,但是Stub可以配置为返回适合测试的值,而不是返回调用时组件将返回的值。使用存根,单元测试可以测试一个单元是否可以处理来自合作者的各种返回值。在单元测试中使用存根而不是真正的合作者可以这样表示:

单元测试——>存根

单元测试——>单元——>存根

单元测试对结果和单元状态进行断言

首先,单元测试创建存根并配置其返回值。然后单元测试创建单元并在其上设置存根。现在,单元测试调用单元,而单元又调用存根。最后,单元测试对单元上的方法调用的结果进行断言。

A Mock is like a stub, only it also has methods that make it possible determine what methods where called on the Mock. Using a mock it is thus possible to both test if the unit can handle various return values correctly, and also if the unit uses the collaborator correctly. For instance, you cannot see by the value returned from a dao object whether the data was read from the database using a Statement or a PreparedStatement. Nor can you see if the connection.close() method was called before returning the value. This is possible with mocks. In other words, mocks makes it possible to test a units complete interaction with a collaborator. Not just the collaborator methods that return values used by the unit. Using a mock in a unit test could be expressed like this:

单元测试——>模拟

单元测试—>单元—>模拟

单元测试对单元的结果和状态进行断言

单元测试断言在mock上调用的方法

>>这里