我读过各种关于测试中模仿和存根的文章,包括Martin Fowler的《Mocks Aren't Stubs》,但我仍然不理解其中的区别。
当前回答
看了上面所有的解释,让我试着总结一下:
Stub:让测试运行的一段虚拟代码,但您并不关心它会发生什么。替代实际工作代码。 Mock:在测试中验证是否正确调用的一段虚拟代码。替代实际工作代码。 间谍:一段虚拟代码,用于拦截和验证对实际工作代码的某些调用,从而避免替换所有实际代码。
其他回答
Stub
我相信最大的区别是您已经编写了带有预定行为的存根。所以你会有一个实现依赖的类(很可能是抽象类或接口),你是为了测试目的而伪造的,方法只是用设置的响应来存根。它们不会做任何花哨的事情,而且您应该已经在测试之外为它编写了存根代码。
Mock
模拟是测试的一部分,你必须根据你的期望来设置。mock并不是预先设定好的,所以您可以在测试中使用它。模拟在某种程度上是在运行时确定的,因为设置期望的代码必须在它们执行任何操作之前运行。
mock和stub的区别
使用模拟编写的测试通常遵循初始化->设置期望->练习->验证模式进行测试。而预先编写的存根将遵循初始化->练习->验证。
mock和stub之间的相似性
这两种方法的目的都是为了消除对类或函数的所有依赖项的测试,从而使您的测试在试图证明的内容方面更加集中和简单。
在我的回答中,我使用了python示例来说明差异。
Stub - Stubbing is a software development technique used to implement methods of classes early in the development life-cycle. They are used commonly as placeholders for implementation of a known interface, where the interface is finalized or known but the implementation is not yet known or finalized. You begin with stubs, which simply means that you only write the definition of a function down and leave the actual code for later. The advantage is that you won't forget methods and you can continue to think about your design while seeing it in code. You can also have your stub return a static response so that the response can be used by other parts of your code immediately. Stub objects provide a valid response, but it's static no matter what input you pass in, you'll always get the same response:
class Foo(object):
def bar1(self):
pass
def bar2(self):
#or ...
raise NotImplementedError
def bar3(self):
#or return dummy data
return "Dummy Data"
模拟对象用于模拟测试用例,它们验证在这些对象上调用了某些方法。模拟对象是以可控的方式模拟真实对象行为的模拟对象。您通常创建一个模拟对象来测试其他对象的行为。mock让我们模拟对于单元测试来说不可用或太笨重的资源。
mymodule.py:
import os
import os.path
def rm(filename):
if os.path.isfile(filename):
os.remove(filename)
test.py:
from mymodule import rm
import mock
import unittest
class RmTestCase(unittest.TestCase):
@mock.patch('mymodule.os')
def test_rm(self, mock_os):
rm("any path")
# test that rm called os.remove with the right parameters
mock_os.remove.assert_called_with("any path")
if __name__ == '__main__':
unittest.main()
这是一个非常基本的示例,它只运行rm并断言调用它的参数。您可以对对象使用mock,而不仅仅是这里所示的函数,您还可以返回一个值,这样模拟对象就可以用来替换存根进行测试。
更多关于unittest的信息。模拟,注意python 2。X mock不包含在unittest中,但它是一个可下载的模块,可以通过PIP (PIP install mock)下载。
我还读过Roy Osherove写的《单元测试的艺术》,我认为如果有一本类似的书是用Python和Python示例编写的,那就太棒了。如果有人知道这样的书,请分享。欢呼:)
测试对象根据某些提示(函数调用)或其他刺激来执行动作。下面是测试情况的具体例子。
场景——EMT学生考试
一名学生学习成为一名紧急医疗技术员。如果你对这个测试情况不熟悉,可以去看Ian Gallagher在《无耻之徒》第六季第十集的节目。
为了测试目的,寻找各种疾病的患者太昂贵了。相反,我们使用角色。我们问测试对象(Ian)"当你到达现场发现病人已经不能动弹,失去知觉你首先要做什么?"伊恩回答说:“我检查现场是否安全。”测试指导老师说“现场是安全的”。
教师(和演员)能够向测试对象的问题注入任意答案。
在这里,教练(和演员)是一个模拟。医学培训与计算机科学家一样使用这个术语(例如模拟代码模拟)。
场景——注册一个网站
你正在测试雅虎,一个你听说过的新的电子邮件服务。为了注册,你必须提供你的生日和其他侵入性问题的答案。
该网站要求你年满21岁。输入1970年1月1日。它满足了需求,并且将您从实现记住我的生日并输入它的工作流的费力过程中拯救出来。
这个日期是存根。这个词的用法只适用于计算机科学。
Stub
存根是用来伪造具有预先编程行为的方法的对象。为了避免不必要的副作用(例如,存根可能会进行一个虚假的获取调用,返回预先编程的响应,而不实际向服务器发出请求),您可能会使用这个方法来代替现有的方法。
Mock
mock是用来模拟具有预编程行为和预编程期望的方法的对象。如果这些期望没有得到满足,那么mock将导致测试失败(例如,mock可以进行一个虚假的获取调用,返回预先编程的响应,而不实际向服务器发出请求,例如,第一个参数是“http://localhost:3008/”,否则测试将失败。)
区别
与模拟不同,存根没有预先编程的可能导致测试失败的期望。
以下是我的理解……
如果您在本地创建测试对象并将其提供给本地服务,则使用的是模拟对象。 这将为您在本地服务中实现的方法提供测试。 它用于验证行为 当您从真正的服务提供者获得测试数据时(尽管是从接口的测试版本获得对象的测试版本),您是在使用存根 存根可以有逻辑来接受特定的输入并给出相应的输出来帮助您执行状态验证…
推荐文章
- 如何使用“测试”包打印Go测试?
- 如何在IntelliJ中为整个项目配置“缩短命令行”方法
- toBe(true) vs toBeTruthy() vs toBeTrue()
- 使用Mockito测试抽象类
- 什么时候应该使用Debug.Assert()?
- 使用Moq模拟扩展方法
- 从控制台停止一个Android应用程序
- 基于输入参数模拟python函数
- 使Android模拟器运行得更快
- 如何“去测试”我的项目中的所有测试?
- 断言对模拟方法的连续调用
- 测试HTML电子邮件渲染
- 测试过程。环境与玩笑
- Rspec:“数组。应该== another_array"而不考虑顺序
- 如何检查字符串数组是否包含JavaScript字符串?