13518219792

建站动态

根据您的个性需求进行定制 先人一步 抢占小程序红利时代

创新互联Python教程:unittest.mock —- 模拟对象库

unittest.mock —- 模拟对象库

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 将创建所有属性和方法,并保存他们在使用时的细节。你可以通过配置,指定返回值或者限制可访问属性,然后断言他们如何被调用:

 
 
 
 
  1. >>> from unittest.mock import MagicMock
  2. >>> thing = ProductionClass()
  3. >>> thing.method = MagicMock(return_value=3)
  4. >>> thing.method(3, 4, 5, key='value')
  5. 3
  6. >>> thing.method.assert_called_with(3, 4, 5, key='value')

通过 side_effect 设置副作用(side effects) ,可以是一个 mock 被调用是抛出的异常:

 
 
 
 
  1. >>> mock = Mock(side_effect=KeyError('foo'))
  2. >>> mock()
  3. Traceback (most recent call last):
  4. ...
  5. KeyError: 'foo'
 
 
 
 
  1. >>> values = {'a': 1, 'b': 2, 'c': 3}
  2. >>> def side_effect(arg):
  3. ... return values[arg]
  4. ...
  5. >>> mock.side_effect = side_effect
  6. >>> mock('a'), mock('b'), mock('c')
  7. (1, 2, 3)
  8. >>> mock.side_effect = [5, 4, 3, 2, 1]
  9. >>> mock(), mock(), mock()
  10. (5, 4, 3)

Mock 还可以通过其他方法配置和控制其行为。例如 mock 可以通过设置 spec 参数来从一个对象中获取其规格(specification)。如果访问 mock 的属性或方法不在 spec 中,会报 AttributeError 错误。

使用 patch() 装饰去/上下文管理器,可以更方便地测试一个模块下的类或对象。你指定的对象会在测试过程中替换成 mock (或者其他对象),测试结束后恢复。

 
 
 
 
  1. >>> from unittest.mock import patch
  2. >>> @patch('module.ClassName2')
  3. ... @patch('module.ClassName1')
  4. ... def test(MockClass1, MockClass2):
  5. ... module.ClassName1()
  6. ... module.ClassName2()
  7. ... assert MockClass1 is module.ClassName1
  8. ... assert MockClass2 is module.ClassName2
  9. ... assert MockClass1.called
  10. ... assert MockClass2.called
  11. ...
  12. >>> test()

备注

当你嵌套 patch 装饰器时,mock 将以执行顺序传递给装饰器函数(Python 装饰器正常顺序)。由于从下至上,因此在上面的示例中,首先 mock 传入的 module.ClassName1

在查找对象的名称空间中修补对象使用 patch() 。使用起来很简单,阅读 在哪里打补丁 来快速上手。

patch() 也可以 with 语句中使用上下文管理。

 
 
 
 
  1. >>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method:
  2. ... thing = ProductionClass()
  3. ... thing.method(1, 2, 3)
  4. ...
  5. >>> mock_method.assert_called_once_with(1, 2, 3)

还有一个 patch.dict() 用于在一定范围内设置字典中的值,并在测试结束时将字典恢复为其原始状态:

 
 
 
 
  1. >>> foo = {'key': 'value'}
  2. >>> original = foo.copy()
  3. >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):
  4. ... assert foo == {'newkey': 'newvalue'}
  5. ...
  6. >>> assert foo == original

Mock支持 Python 魔术方法 。使用模式方法最简单的方式是使用 MagicMock class. 。它可以做如下事情:

 
 
 
 
  1. >>> mock = MagicMock()
  2. >>> mock.__str__.return_value = 'foobarbaz'
  3. >>> str(mock)
  4. 'foobarbaz'
  5. >>> mock.__str__.assert_called_with()

Mock 能指定函数(或其他 Mock 实例)为魔术方法,它们将被适当地调用。 MagicMock 是预先创建了所有魔术方法(所有有用的方法) 的 Mock 。

下面是一个使用了普通 Mock 类的魔术方法的例子

 
 
 
 
  1. >>> mock = Mock()
  2. >>> mock.__str__ = Mock(return_value='wheeeeee')
  3. >>> str(mock)
  4. 'wheeeeee'

使用 auto-speccing 可以保证测试中的模拟对象与要替换的对象具有相同的api 。在 patch 中可以通过 autospec 参数实现自动推断,或者使用 create_autospec() 函数。自动推断会创建一个与要替换对象相同的属相和方法的模拟对象,并且任何函数和方法(包括构造函数)都具有与真实对象相同的调用签名。

这么做是为了因确保不当地使用 mock 导致与生产代码相同的失败:

 
 
 
 
  1. >>> from unittest.mock import create_autospec
  2. >>> def function(a, b, c):
  3. ... pass
  4. ...
  5. >>> mock_function = create_autospec(function, return_value='fishy')
  6. >>> mock_function(1, 2, 3)
  7. 'fishy'
  8. >>> mock_function.assert_called_once_with(1, 2, 3)
  9. >>> mock_function('wrong arguments')
  10. Traceback (most recent call last):
  11. ...
  12. TypeError: () takes exactly 3 arguments (1 given)

在类中使用 create_autospec() 时,会复制 __init__ 方法的签名,另外在可调用对象上使用时,会复制 __call__ 方法的签名。

Mock 类

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 对象的行为:

还可以使用任意关键字参数来调用 mock 。 创建模拟后,将使用这些属性来设置 mock 的属性。 有关详细信息,请参见 configure_mock() 方法。

class unittest.mock.NonCallableMock(spec=None, wraps=None, name=None, spec_set=None, \*kwargs*)

不可调用的 Mock 版本。 其构造器的形参具有与 Mock 相同的含义,区别在于 return_valueside_effect 在不可调用的 mock 上没有意义。

使用类或实例作为 specspec_set 的 mock 对象能够跳过 isinstance() 测试:

 
 
 
 
  1. >>> mock = Mock(spec=SomeClass)
  2. >>> isinstance(mock, SomeClass)
  3. True
  4. >>> mock = Mock(spec_set=SomeClass())
  5. >>> isinstance(mock, SomeClass)
  6. True

Mock 类具有对 mock 操作魔术方法的支持。 请参阅 魔术方法 了解完整细节。

mock 操作类和 patch() 装饰器都接受任意关键字参数用于配置。 对于 patch() 装饰器来说关键字参数会被传给所创建 mock 的构造器。 这些关键字被用于配置 mock 的属性:

 
 
 
 
  1. >>> m = MagicMock(attribute=3, other='fish')
  2. >>> m.attribute
  3. 3
  4. >>> m.other
  5. 'fish'

子 mock 的返回值和附带效果也可使用带点号的标记通过相同的方式来设置。 由于你无法直接在调用中使用带点号的名称因此你需要创建一个字典并使用 ** 来解包它:

 
 
 
 
  1. >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
  2. >>> mock = Mock(some_attribute='eggs', **attrs)
  3. >>> mock.some_attribute
  4. 'eggs'
  5. >>> mock.method()
  6. 3
  7. >>> mock.other()
  8. Traceback (most recent call last):
  9. ...
  10. KeyError

使用 spec (或 spec_set) 创建的可调用 mock 将在匹配调用与 mock 时内省规格说明对象的签名。 因此,它可以匹配实际调用的参数而不必关心它们是按位置还是按名称传入的:

 
 
 
 
  1. >>> def f(a, b, c): pass
  2. ...
  3. >>> mock = Mock(spec=f)
  4. >>> mock(1, 2, c=3)
  5. >>> mock.assert_called_with(1, 2, 3)
  6. >>> mock.assert_called_with(a=1, b=2, c=3 网站栏目:创新互联Python教程:unittest.mock —- 模拟对象库
    标题网址:http://cdbrznjsb.com/article/dpcgsjo.html
  • 网站建设专属方案

  • 网站定制化设计

  • 7X24小时服务

  • N对管家服务

让你的专属顾问为你服务