3.3 新版功能.
成都创新互联主要从事成都网站设计、网站制作、网页设计、企业做网站、公司建网站等业务。立足成都服务叶城,十余年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:13518219792
源代码: Lib/unittest/mock.py
unittest.mock 是一个用于测试的python库。它允许使用模拟对象来替换受测系统的一些部分,并对这些部分如何被使用进行断言判断。
unittest.mock 提供的 Mock 类,能在整个测试套件中模拟大量的方法。创建后,就可以断言调用了哪些方法/属性及其参数。还可以以常规方式指定返回值并设置所需的属性。
此外,mock 还提供了用于修补测试范围内模块和类级别属性的 patch() 装饰器,和用于创建独特对象的 sentinel 。 阅读 quick guide 中的案例了解如何使用 Mock ,MagicMock 和 patch() 。
mock 被设计为配合 unittest 使用且它是基于 ‘action -> assertion’ 模式而非许多模拟框架所使用的 ‘record -> replay’ 模式。
在 Python 的早期版本要单独使用 unittest.mock ,在 PyPI 获取 mock 。
当您访问对象时, Mock 和 MagicMock 将创建所有属性和方法,并保存他们在使用时的细节。你可以通过配置,指定返回值或者限制可访问属性,然后断言他们如何被调用:
>>> from unittest.mock import MagicMock
>>> thing = ProductionClass()
>>> thing.method = MagicMock(return_value=3)
>>> thing.method(3, 4, 5, key='value')
3
>>> thing.method.assert_called_with(3, 4, 5, key='value')
通过 side_effect
设置副作用(side effects) ,可以是一个 mock 被调用是抛出的异常:
>>> mock = Mock(side_effect=KeyError('foo'))
>>> mock()
Traceback (most recent call last):
...
KeyError: 'foo'
>>> values = {'a': 1, 'b': 2, 'c': 3}
>>> def side_effect(arg):
... return values[arg]
...
>>> mock.side_effect = side_effect
>>> mock('a'), mock('b'), mock('c')
(1, 2, 3)
>>> mock.side_effect = [5, 4, 3, 2, 1]
>>> mock(), mock(), mock()
(5, 4, 3)
Mock 还可以通过其他方法配置和控制其行为。例如 mock 可以通过设置 spec 参数来从一个对象中获取其规格(specification)。如果访问 mock 的属性或方法不在 spec 中,会报 AttributeError 错误。
使用 patch() 装饰去/上下文管理器,可以更方便地测试一个模块下的类或对象。你指定的对象会在测试过程中替换成 mock (或者其他对象),测试结束后恢复。
>>> from unittest.mock import patch
>>> @patch('module.ClassName2')
... @patch('module.ClassName1')
... def test(MockClass1, MockClass2):
... module.ClassName1()
... module.ClassName2()
... assert MockClass1 is module.ClassName1
... assert MockClass2 is module.ClassName2
... assert MockClass1.called
... assert MockClass2.called
...
>>> test()
备注
当你嵌套 patch 装饰器时,mock 将以执行顺序传递给装饰器函数(Python 装饰器正常顺序)。由于从下至上,因此在上面的示例中,首先 mock 传入的 module.ClassName1
。
在查找对象的名称空间中修补对象使用 patch() 。使用起来很简单,阅读 在哪里打补丁 来快速上手。
patch() 也可以 with 语句中使用上下文管理。
>>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method:
... thing = ProductionClass()
... thing.method(1, 2, 3)
...
>>> mock_method.assert_called_once_with(1, 2, 3)
还有一个 patch.dict() 用于在一定范围内设置字典中的值,并在测试结束时将字典恢复为其原始状态:
>>> foo = {'key': 'value'}
>>> original = foo.copy()
>>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):
... assert foo == {'newkey': 'newvalue'}
...
>>> assert foo == original
Mock支持 Python 魔术方法 。使用模式方法最简单的方式是使用 MagicMock class. 。它可以做如下事情:
>>> mock = MagicMock()
>>> mock.__str__.return_value = 'foobarbaz'
>>> str(mock)
'foobarbaz'
>>> mock.__str__.assert_called_with()
Mock 能指定函数(或其他 Mock 实例)为魔术方法,它们将被适当地调用。 MagicMock 是预先创建了所有魔术方法(所有有用的方法) 的 Mock 。
下面是一个使用了普通 Mock 类的魔术方法的例子
>>> mock = Mock()
>>> mock.__str__ = Mock(return_value='wheeeeee')
>>> str(mock)
'wheeeeee'
使用 auto-speccing 可以保证测试中的模拟对象与要替换的对象具有相同的api 。在 patch 中可以通过 autospec 参数实现自动推断,或者使用 create_autospec() 函数。自动推断会创建一个与要替换对象相同的属相和方法的模拟对象,并且任何函数和方法(包括构造函数)都具有与真实对象相同的调用签名。
这么做是为了因确保不当地使用 mock 导致与生产代码相同的失败:
>>> from unittest.mock import create_autospec
>>> def function(a, b, c):
... pass
...
>>> mock_function = create_autospec(function, return_value='fishy')
>>> mock_function(1, 2, 3)
'fishy'
>>> mock_function.assert_called_once_with(1, 2, 3)
>>> mock_function('wrong arguments')
Traceback (most recent call last):
...
TypeError:
() takes exactly 3 arguments (1 given)
在类中使用 create_autospec() 时,会复制 __init__
方法的签名,另外在可调用对象上使用时,会复制 __call__
方法的签名。
Mock 是一个可以灵活的替换存根 (stubs) 的对象,可以测试所有代码。 Mock 是可调用的,在访问其属性时创建一个新的 mock 1 。访问相同的属性只会返回相同的 mock 。 Mock 会保存调用记录,可以通过断言获悉代码的调用。
MagicMock 是 Mock 的子类,它有所有预创建且可使用的魔术方法。在需要模拟不可调用对象时,可以使用 NonCallableMock 和 NonCallableMagicMock
patch() 装饰器使得用 Mock 对象临时替换特定模块中的类非常方便。 默认情况下 patch() 将为你创建一个 MagicMock。 你可以使用 patch() 的 new_callable 参数指定替代 Mock 的类。
class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, \*kwargs*)
创建一个新的 Mock 对象。通过可选参数指定 Mock 对象的行为:
spec: 可以是要给字符串列表,也可以是充当模拟对象规范的现有对象(类或实例)。如果传入一个对象,则通过在该对象上调用 dir 来生成字符串列表(不支持的魔法属性和方法除外)。访问不在此列表中的任何属性都将触发 AttributeError 。
如果 spec 是一个对象(而不是字符串列表),则 __class__ 返回 spec 对象的类。 这允许模拟程序通过 isinstance() 测试。
spec_set :spec 的更严格的变体。如果使用了该属性,尝试模拟 set 或 get 的属性不在 spec_set 所包含的对象中时,会抛出 AttributeError 。
side_effect :每当调用 Mock 时都会调用的函数。 参见 side_effect 属性。 对于引发异常或动态更改返回值很有用。 该函数使用与 mock 函数相同的参数调用,并且除非返回 DEFAULT ,否则该函数的返回值将用作返回值。
另外, side_effect 可以是异常类或实例。 此时,调用模拟程序时将引发异常。
如果 side_effect 是可迭代对象,则每次调用 mock 都将返回可迭代对象的下一个值。
设置 side_effect 为 None
即可清空。
return_value :调用 mock 的返回值。 默认情况下,是一个新的Mock(在首次访问时创建)。 参见 return_value 属性 。
unsafe: By default, accessing any attribute whose name starts with assert, assret, asert, aseert or assrt will raise an AttributeError. Passing unsafe=True
will allow access to these attributes.
3.5 新版功能.
wraps :要包装的 mock 对象。 如果 wraps 不是 None
,那么调用 Mock 会将调用传递给 wraps 的对象(返回实际结果)。 对模拟的属性访问将返回一个 Mock 对象,该对象包装了 wraps 对象的相应属性(因此,尝试访问不存在的属性将引发 AttributeError )。
如果明确指定 return_value ,则调用时不会返回包装对象,而是返回 return_value 。
name :mock 的名称。 在调试时很有用。 名称会传递到子 mock 。
还可以使用任意关键字参数来调用 mock 。 创建模拟后,将使用这些属性来设置 mock 的属性。 有关详细信息,请参见 configure_mock() 方法。
assert_called()
断言 mock 已被调用至少一次。
>>> mock = Mock()
>>> mock.method()
>>> mock.method.assert_called()
3.6 新版功能.
assert_called_once()
断言 mock 已被调用恰好一次。
>>> mock = Mock()
>>> mock.method()
>>> mock.method.assert_called_once()
>>> mock.method()
>>> mock.method.assert_called_once()
Traceback (most recent call last):
...
AssertionError: Expected 'method' to have been called once. Called 2 times.
3.6 新版功能.
assert_called_with(\args,**kwargs*)
此方法是断言上次调用已以特定方式进行的一种便捷方法:
>>> mock = Mock()
>>> mock.method(1, 2, 3, test='wow')
>>> mock.method.assert_called_with(1, 2, 3, test='wow')
assert_called_once_with(\args,**kwargs*)
断言 mock 已被调用恰好一次,并且向该调用传入了指定的参数。
>>> mock = Mock(return_value=None)
>>> mock('foo', bar='baz')
>>> mock.assert_called_once_with('foo', bar='baz')
>>> mock('other', bar='values')
>>> mock.assert_called_once_with('other', bar='values')
Traceback (most recent call last):
...
AssertionError: Expected 'mock' to be called once. Called 2 times.
assert_any_call(\args,**kwargs*)
断言 mock 已被调用并附带了指定的参数。
如果 mock 曾经 被调用过则断言通过,不同于 assert_called_with() 和 assert_called_once_with() 那样只有在调用是最近的一次时才会通过,而对于 assert_called_once_with() 则它还必须是唯一的一次调用。
>>> mock = Mock(return_value=None)
>>> mock(1, 2, arg='thing')
>>> mock('some', 'thing', 'else')
>>> mock.assert_any_call(1, 2, arg='thing')
assert_has_calls(calls, any_order=False)
断言 mock 已附带指定的参数被调用。 将针对这些调用检查 mock_calls 列表。
如果 any_order 为假值则调用必须是顺序进行的。 在指定的调用之前或之后还可以有额外的调用。
如果 any_order 为真值则调用可以是任意顺序的,但它们都必须在 mock_calls 中出现。
>>> mock = Mock(return_value=None)
>>> mock(1)
>>> mock(2)
>>> mock(3)
>>> mock(4)
>>> calls = [call(2), call(3)]
>>> mock.assert_has_calls(calls)
>>> calls = [call(4), call(2), call(3)]
>>> mock.assert_has_calls(calls, any_order=True)
assert_not_called()
断言 mock 从未被调用过。
>>> m = Mock()
>>> m.hello.assert_not_called()
>>> obj = m.hello()
>>> m.hello.assert_not_called()
Traceback (most recent call last):
...
AssertionError: Expected 'hello' to not have been called. Called 1 times.
3.5 新版功能.
reset_mock(**,return_value=False,side_effect=False*)
reset_mock 方法将在 mock 对象上重围所有的调用属性:
>>> mock = Mock(return_value=None)
>>> mock('hello')
>>> mock.called
True
>>> mock.reset_mock()
>>> mock.called
False
在 3.6 版更改: 向 reset_mock 函数添加了两个仅限关键字参数。
这在你想要创建一系列重用相同对象的断言时会很有用处。 请注意 reset_mock() 不会 清除返回值、side_effect 或任何你使用普通赋值所默认设置的子属性。 如果你想要重置 return_value 或 side_effect,则要为相应的形参传入 True
。 子 mock 和返回值 mock (如果有的话) 也会被重置。
备注
return_value 和 side_effect 均为仅限关键字参数。
mock_add_spec(spec, spec_set=False)
为 mock 添加描述。 spec 可以是一个对象或字符串列表。 只有 spec 上的属性可以作为来自 mock 的属性被获取。
如果 spec_set 为真值则只有 spec 上的属性可以被设置。
attach_mock(mock, attribute)
附加一个 mock 作为这一个的属性,替换它的名称和上级。 对附加 mock 的调用将记录在这一个的 method_calls 和 mock_calls 属性中。
configure_mock(\*kwargs*)
通过关键字参数在 mock 上设置属性。
属性加返回值和附带影响可以使用标准点号标记在子 mock 上设置并在方法调用中解包一个字典:
>>> mock = Mock()
>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> mock.configure_mock(**attrs)
>>> mock.method()
3
>>> mock.other()
Traceback (most recent call last):
...
KeyError
同样的操作可在对 mock 的构造器调用中达成:
>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> mock = Mock(some_attribute='eggs', **attrs)
>>> mock.some_attribute
'eggs'
>>> mock.method()
3
>>> mock.other()
Traceback (most recent call last):
...
KeyError
configure_mock() 的存在是使得 mock 被创建之后的配置更为容易。
__dir__()
Mock 对象会将 dir(some_mock)
的结果限制为有用结果。 对于带有 spec 的 mock 这还包括 mock 的所有被允许的属性。
请查看 FILTER_DIR 了解此过滤做了什么,以及如何停用它。
_get_child_mock(\*kw*)
创建针对属性和返回值的子 mock。 默认情况下子 mock 将为与其上级相同的类型。 Mock 的子类可能需要重载它来定制子 mock 的创建方式。
对于非可调用的 mock 将会使用可调用的变化形式(而非不是任意的自定义子类)。
called
一个表示 mock 对象是否已被调用的布尔值:
>>> mock = Mock(return_value=None)
>>> mock.called
False
>>> mock()
>>> mock.called
True
call_count
一个告诉你 mock 对象已被调用多少次的整数值:
>>> mock = Mock(return_value=None)
>>> mock.call_count
0
>>> mock()
>>> mock()
>>> mock.call_count
2
return_value
设置这个来配置通过调用该 mock 所返回的值:
>>> mock = Mock()
>>> mock.return_value = 'fish'
>>> mock()
'fish'
默认的返回值是一个 mock 对象并且你可以通过正常方式来配置它:
>>> mock = Mock()
>>> mock.return_value.attribute = sentinel.Attribute
>>> mock.return_value()
>>> mock.return_value.assert_called_with()
return_value 也可以在构造器中设置:
>>> mock = Mock(return_value=3)
>>> mock.return_value
3
>>> mock()
3
side_effect
这可以是当该This can either be a function to be called when the mock 被调用时将被调用的一个函数,可调用对象或者要被引发的异常(类或实例)。
如果你传入一个函数则它将附带与该 mock 相同的参数被调用并且除了该函数返回 DEFAULT 单例的情况以外对该 mock 的调用都将随后返回该函数所返回的任何东西。 如果该函数返回 DEFAULT 则该 mock 将返回其正常值 (来自 return_value)。
如果你传入一个可迭代对象,它会被用来获取一个在每次调用时必须产生一个值的迭代器。 这个值可以是一个要被引发的异常实例,或是一个要从该调用返回给 mock 的值 (DEFAULT 处理与函数的情况一致)。
一个引发异常(来测试 API 的异常处理)的 mock 的示例:
>>> mock = Mock()
>>> mock.side_effect = Exception('Boom!')
>>> mock()
Traceback (most recent call last):
...
Exception: Boom!
使用 side_effect 来返回包含多个值的序列:
>>> mock = Mock()
>>> mock.side_effect = [3, 2, 1]
>>> mock(), mock(), mock()
(3, 2, 1)
使用一个可调用对象:
>>> mock = Mock(return_value=3)
>>> def side_effect(*args, **kwargs):
... return DEFAULT
...
>>> mock.side_effect = side_effect
>>> mock()
3
side_effect 可以在构造器中设置。 下面是在 mock 被调用时增加一个该属性值并返回它的例子:
>>> side_effect = lambda value: value + 1
>>> mock = Mock(side_effect=side_effect)
>>> mock(3)
4
>>> mock(-8)
-7
将 side_effect 设为 None
可以清除它:
>>> m = Mock(side_effect=KeyError, return_value=3)
>>> m()
Traceback (most recent call last):
...
KeyError
>>> m.side_effect = None
>>> m()
3
call_args
这可以是 None
(如果 mock 没有被调用),或是 mock 最近一次被调用时附带的参数。 这将采用元组的形式:第一个成员也可以通过 args
特征属性来访问,它是 mock 被调用时所附带的任何位置参数 (或为空元组),而第二个成员也可以通过 kwargs
特征属性来访问,它则是任何关键字参数 (或为空字典)。
>>> mock = Mock(return_value=None)
>>> print(mock.call_args)
None
>>> mock()
>>> mock.call_args
call()
>>> mock.call_args == ()
True
>>> mock(3, 4)
>>> mock.call_args
call(3, 4)
>>> mock.call_args == ((3, 4),)
True
>>> mock.call_args.args
(3, 4)
>>> mock.call_args.kwargs
{}
>>> mock(3, 4, 5, key='fish', next='w00t!')
>>> mock.call_args
call(3, 4, 5, key='fish', next='w00t!')
>>> mock.call_args.args
(3, 4, 5)
>>> mock.call_args.kwargs
{'key': 'fish', 'next': 'w00t!'}
call_args,以及列表 call_args_list, method_calls 和 mock_calls 的成员都是 call 对象。 这些对象属性元组,因此它们可被解包以获得单独的参数并创建更复杂的断言。 参见 作为元组的 call。
在 3.8 版更改: 增加了 args
和 kwargs
特征属性。properties.
call_args_list
这是一个已排序的对 mock 对象的所有调用的列表(因此该列表的长度就是它已被调用的次数)。 在执行任何调用之前它将是一个空列表。 call 对象可以被用来方便地构造调用列表以与 call_args_list 相比较。
>>> mock = Mock(return_value=None)
>>> mock()
>>> mock(3, 4)
>>> mock(key='fish', next='w00t!')
>>> mock.call_args_list
[call(), call(3, 4), call(key='fish', next='w00t!')]
>>> expected = [(), ((3, 4),), ({'key': 'fish', 'next': 'w00t!'},)]
>>> mock.call_args_list == expected
True
call_args_list 的成员均为 call 对象。 它们可作为元组被解包以获得单个参数。 参见 作为元组的 call。
method_calls
除了会追踪对其自身的调用,mock 还会追踪对方法和属性,以及 它们的 方法和属性的访问:
>>> mock = Mock()
>>> mock.method()
>>> mock.property.method.attribute()
>>> mock.method_calls
[call.method(), call.property.method.attribute()]
method_calls 的成员均为 call 对象。 它们可以作为元组被解包以获得单个参数。 参见 作为元组的 call。
mock_calls
mock_calls 会记录 所有 对 mock 对象、它的方法、魔术方法的调用 以及 返回值的 mock。
>>> mock = MagicMock()
>>> result = mock(1, 2, 3)
>>> mock.first(a=3)
>>> mock.second()
>>> int(mock)
1
>>> result(1)
>>> expected = [call(1, 2, 3), call.first(a=3), call.second(),
... call.__int__(), call()(1)]
>>> mock.mock_calls == expected
True
mock_calls 的成员均为 call 对象。 它们可以作为元组被解包以获得单个参数。 参见 作为元组的 call。
备注
mock_calls 的记录方式意味着在进行嵌套调用时,之前调用的形参不会被记录因而这样的比较将总是相等:
>>> mock = MagicMock()
>>> mock.top(a=3).bottom()
>>> mock.mock_calls
[call.top(a=3), call.top().bottom()]
>>> mock.mock_calls[-1] == call.top(a=-1).bottom()
True
__class__
通常一个对象的 __class__ 属性将返回其类型。 对于具有 spec
的 mock 对象来说,__class__
将改为返回 spec 类。 这将允许 mock 对象为它们所替换 / 屏蔽的对象跳过 isinstance() 测试:
>>> mock = Mock(spec=3)
>>> isinstance(mock, int)
True
__class__ 是可以被赋值的,这将允许 mock 跳过 isinstance() 检测而不强制要求你使用 spec:
>>> mock = Mock()
>>> mock.__class__ = dict
>>> isinstance(mock, dict)
True
class unittest.mock.NonCallableMock(spec=None, wraps=None, name=None, spec_set=None, \*kwargs*)
不可调用的 Mock 版本。 其构造器的形参具有与 Mock 相同的含义,区别在于 return_value 和 side_effect 在不可调用的 mock 上没有意义。
使用类或实例作为 spec
或 spec_set
的 mock 对象能够跳过 isinstance() 测试:
>>> mock = Mock(spec=SomeClass)
>>> isinstance(mock, SomeClass)
True
>>> mock = Mock(spec_set=SomeClass())
>>> isinstance(mock, SomeClass)
True
Mock 类具有对 mock 操作魔术方法的支持。 请参阅 魔术方法 了解完整细节。
mock 操作类和 patch() 装饰器都接受任意关键字参数用于配置。 对于 patch() 装饰器来说关键字参数会被传给所创建 mock 的构造器。 这些关键字被用于配置 mock 的属性:
>>> m = MagicMock(attribute=3, other='fish')
>>> m.attribute
3
>>> m.other
'fish'
子 mock 的返回值和附带效果也可使用带点号的标记通过相同的方式来设置。 由于你无法直接在调用中使用带点号的名称因此你需要创建一个字典并使用 **
来解包它:
>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> mock = Mock(some_attribute='eggs', **attrs)
>>> mock.some_attribute
'eggs'
>>> mock.method()
3
>>> mock.other()
Traceback (most recent call last):
...
KeyError
使用 spec (或 spec_set) 创建的可调用 mock 将在匹配调用与 mock 时内省规格说明对象的签名。 因此,它可以匹配实际调用的参数而不必关心它们是按位置还是按名称传入的:
>>> def f(a, b, c): pass
...
>>> mock = Mock(spec=f)
>>> mock(1, 2, c=3)
>>> mock.assert_called_with(1, 2, 3)
>>> mock.assert_called_with(a=1, b=2, c=3
本文名称:创新互联Python教程:unittest.mock —- 模拟对象库
分享URL:http://www.gawzjz.com/qtweb/news45/195445.html网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联