正如投票率最高的答案所提到的,Martin Fowler 在Mocks Aren't Stubs中讨论了这些区别,特别是副标题The Difference Between Mocks and Stubs,因此请务必阅读该文章。
与其关注这些事物的不同之处,我认为关注为什么这些是不同的概念会更有启发性。每一个都是为了不同的目的而存在的。
假货
fake是一种行为“自然”但不是“真实”的实现。这些都是模糊的概念,所以不同的人对什么是假的有不同的理解。
伪造的一个例子是内存数据库(例如使用带有:memory:
存储的sqlite)。你永远不会将它用于生产(因为数据没有持久化),但它完全可以作为在测试环境中使用的数据库。它也比“真正的”数据库轻得多。
再举一个例子,也许您在生产中使用某种对象存储(例如 Amazon S3),但在测试中您可以简单地将对象保存到磁盘上的文件中;那么您的“保存到磁盘”实现将是假的。(或者你甚至可以通过使用内存文件系统来伪造“保存到磁盘”操作。)
作为第三个示例,想象一个提供缓存 API 的对象;实现正确接口但根本不执行缓存但总是返回缓存未命中的对象将是一种假的。
伪造的目的不是影响被测系统的行为,而是简化测试的实现(通过删除不必要的或重量级的依赖项)。
存根
存根是一种行为“不自然”的实现。它被预先配置(通常由测试设置)以响应具有特定输出的特定输入。
存根的目的是让您的被测系统进入特定状态。例如,如果您正在为与 REST API 交互的某些代码编写测试,您可以使用始终返回预设响应或以特定错误响应 API 请求的 API来存根REST API。这样你就可以编写测试来断言系统如何对这些状态做出反应;例如,测试您的用户在 API 返回 404 错误时得到的响应。
存根通常被实现为仅响应您告诉它响应的确切交互。但是,使某个东西成为存根的关键特性是它的目的:存根就是设置您的测试用例。
模拟
模拟类似于存根,但添加了验证。模拟的目的是断言您的被测系统如何与依赖项交互。
例如,如果您正在为将文件上传到网站的系统编写测试,您可以构建一个接受文件的模拟,并且您可以使用它来断言上传的文件是正确的。或者,在较小的规模上,通常使用对象的模拟来验证被测系统是否调用了模拟对象的特定方法。
模拟与交互测试相关,这是一种特定的测试方法。喜欢测试系统状态而不是系统交互的人会谨慎使用模拟。
测试双打
Fakes、stubs 和 mocks 都属于test doubles的范畴。测试替身是您在测试中使用的任何对象或系统,而不是其他东西。大多数自动化软件测试都涉及使用某种类型的测试替身。其他一些测试替身包括虚拟值、间谍和 I/O黑洞。