我读过各种关于测试中模仿和存根的文章,包括Martin Fowler的《Mocks Aren't Stubs》,但我仍然不理解其中的区别。
当前回答
存根是一个空函数,用于在测试期间避免未处理的异常:
function foo(){}
mock是一个人为的函数,用于避免在测试期间对操作系统、环境或硬件的依赖:
function foo(bar){ window = this; return window.toString(bar); }
在断言和状态方面:
在事件或状态更改之前断言模拟 存根不被断言,它们在事件之前提供状态,以避免执行来自不相关单元的代码 间谍就像存根一样被设置,然后在事件或状态改变后被断言 假的是不断言的,他们运行后的事件硬编码的依赖,以避免状态
参考文献
极客词汇:Mock 极客词汇:存根 极客术语:间谍 测试替身:假的,模拟和存根
其他回答
Mock只是测试行为,确保调用了特定的方法。 Stub是特定对象的可测试版本(本质上)。
你说的苹果方式是什么意思?
在codeschool.com的课程《Rails僵尸测试》中,他们给出了这些术语的定义:
Stub
用于将方法替换为返回指定结果的代码。
Mock
带有调用方法的断言的存根。
因此,正如Sean Copenhaver在他的回答中所描述的那样,不同之处在于mock设置了期望(即做出断言,关于是否或如何调用它们)。
存根是为测试目的而构建的伪对象。mock是记录预期调用是否有效发生的存根。
Stub
存根是用来伪造具有预先编程行为的方法的对象。为了避免不必要的副作用(例如,存根可能会进行一个虚假的获取调用,返回预先编程的响应,而不实际向服务器发出请求),您可能会使用这个方法来代替现有的方法。
Mock
mock是用来模拟具有预编程行为和预编程期望的方法的对象。如果这些期望没有得到满足,那么mock将导致测试失败(例如,mock可以进行一个虚假的获取调用,返回预先编程的响应,而不实际向服务器发出请求,例如,第一个参数是“http://localhost:3008/”,否则测试将失败。)
区别
与模拟不同,存根没有预先编程的可能导致测试失败的期望。
在我的回答中,我使用了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示例编写的,那就太棒了。如果有人知道这样的书,请分享。欢呼:)
推荐文章
- 如何模拟低带宽、高延迟的环境?
- 使用Moq验证方法调用
- 我如何“休眠”Dart程序
- 使用Mockito的泛型“any()”方法
- Mockito中检测到未完成的存根
- 尝试模拟datetime.date.today(),但不工作
- 如何用python timeit对代码段进行性能测试?
- 确定bash中是否存在一个函数
- 如何使用“测试”包打印Go测试?
- 如何在IntelliJ中为整个项目配置“缩短命令行”方法
- toBe(true) vs toBeTruthy() vs toBeTrue()
- 使用Mockito测试抽象类
- 什么时候应该使用Debug.Assert()?
- 使用Moq模拟扩展方法
- 从控制台停止一个Android应用程序