我读过各种关于测试中模仿和存根的文章,包括Martin Fowler的《Mocks Aren't Stubs》,但我仍然不理解其中的区别。
当前回答
上面有很多有效的答案,但我认为值得一提的是这个表格鲍勃叔叔: https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html
最好的例子解释!
其他回答
Stubs vs. Mocks Stubs provide specific answers to methods calls ex: myStubbedService.getValues() just return a String needed by the code under test used by code under test to isolate it cannot fail test ex: myStubbedService.getValues() just returns the stubbed value often implement abstract methods Mocks "superset" of stubs; can assert that certain methods are called ex: verify that myMockedService.getValues() is called only once used to test behaviour of code under test can fail test ex: verify that myMockedService.getValues() was called once; verification fails, because myMockedService.getValues() was not called by my tested code often mocks interfaces
关于这个问题,我认为Roy Osherove在他的书《单元测试的艺术》(85页)中给出了最简单、最清晰的答案。
判断我们正在处理存根的最简单方法是注意到存根永远不会通过测试。测试使用的断言总是反对的 被测试的班级。 另一方面,测试将使用一个模拟对象来验证 测试是否失败。[…] 同样,模拟对象是我们用来检查测试是否失败的对象。
Stub和mock都是假的。
如果您对假的进行断言,这意味着您将假的用作mock,如果您仅使用假的运行测试而没有对其进行断言,那么您将假的用作存根。
前言
有几个对象的定义是不真实的。一般的术语是双重测试。这个术语包括:dummy, fake, stub, mock。
参考
根据Martin Fowler的文章:
Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists. Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example). Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'. Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.
风格
模拟vs存根=行为测试vs状态测试
原则
根据每个测试只测试一件事的原则,一个测试中可能有几个存根,但一般只有一个mock。
生命周期
使用存根测试生命周期:
准备正在测试的对象和它的存根合作者。 锻炼——测试功能。 验证状态——使用断言来检查对象的状态。 Teardown -清理资源。
使用mock测试生命周期:
设置数据-准备正在测试的对象。 设置期望-在mock中准备主对象使用的期望。 锻炼——测试功能。 验证期望——验证在mock中调用了正确的方法。 验证状态——使用断言来检查对象的状态。 Teardown -清理资源。
总结
模拟测试和存根测试都给出了这个问题的答案:结果是什么?
使用模拟进行测试也感兴趣:结果是如何实现的?
存根是为测试目的而构建的伪对象。mock是记录预期调用是否有效发生的存根。
从论文模拟角色,而不是对象,由jMock的开发人员:
存根是返回罐装的产品代码的虚拟实现 结果。Mock对象充当存根,但也包括到的断言 测量目标对象与其邻居的交互作用。
所以,主要的区别是:
在存根上设置的期望通常是通用的,而在mock上设置的期望可能更“聪明”(例如,在第一次调用时返回this,在第二次调用时返回this等)。 存根主要用于设置SUT的间接输入,而mock可用于测试SUT的间接输入和间接输出。
综上所述,同时也试图驱散福勒文章标题中的困惑:mock是存根,但它们不仅仅是存根。
推荐文章
- ReferenceError: description没有定义NodeJs
- Mock vs MagicMock
- 我如何使用Jest模拟JavaScript的“窗口”对象?
- 如何检查动态附加的事件监听器是否存在?
- 强制重新测试或禁用测试缓存
- 比较Java中2个XML文档的最佳方法
- 如何模拟低带宽、高延迟的环境?
- 使用Moq验证方法调用
- 我如何“休眠”Dart程序
- 使用Mockito的泛型“any()”方法
- Mockito中检测到未完成的存根
- 尝试模拟datetime.date.today(),但不工作
- 如何用python timeit对代码段进行性能测试?
- 确定bash中是否存在一个函数
- 如何使用“测试”包打印Go测试?