python mock使用

Overview

mock 是一个用于单元测试的 Python 库,它使用 mock 模拟系统中如 class, method 等部分,而且断言它们是如何被调用的。在编写单元测试时,mock 很是适合模拟数据库,web 服务器等依赖外部的场景。本文是 mock 的入门篇,主要介绍 mock 的基本用法。html

除了 mock 外,还有许多其它的 mocking 库,Python Mock Library Comparison 在用法上对这些库作了简单的比较,其中 OpenStack 单元测试普遍的使用了 mock 和 mox。python

mock 的安装很是简便:git

$ pip install mock 

Mock Patching Methods

当使用 mock 模拟 methods 时,mock 会替换被模拟的 methods,而且记录调用详情。github

>>> class Foo(object): ... def echo(self, *args): ... return "hello" ... >>> >>> foo = Foo() >>> foo.echo = mock.MagicMock() >>> foo.echo.return_value = "mock value" >>> >>> foo.echo() 'mock value' >>> foo.echo(1, 2) 'mock value' 

被模拟后,foo.echo 的类型是一个名为 mock.MagicMock 类,具备 assert_any_call, assert_called_once_with 等方法,其中 assert 类型的方法一般用于检验 foo.echo 是否被正确调用。web

>>> type(foo.echo) <class 'mock.MagicMock'> >>> dir(foo.echo) ['assert_any_call', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', 'configure_mock', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect'] 

断言 foo.echo 被调用的状况,其中 foo.echo 共被调用两次(见上)。数据库

>>> foo.echo.called True >>> foo.echo.call_count 2 >>> foo.echo.mock_calls [call(), call(1, 2)] >>> >>> foo.echo.assert_called_with(1, 2) >>> foo.echo.assert_called_with(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/dist-packages/mock.py", line 844, in assert_called_with raise AssertionError(msg) AssertionError: Expected call: mock(1) Actual call: mock(1, 2) 

mock.Mock 和 mock.MagicMock 是两个经常使用的类,stackoverflow 有篇帖子 mock-vs-magicmock 专门讲述两者的区别:bash

  • MagicMock 是 Mock 的之类
  • MagicMock 额外实现了不少 magic 的方法

Mocking Classes

采用 mock 可方便的模拟 class,例如:服务器

>>> def some_function(): ... foo = Foo() ... return foo.echo() ... >>> with mock.patch('__main__.Foo') as foo_mock: ... instance = foo_mock.return_value ... instance.echo.return_value = "mock result" ... result = some_function() ... assert result == "mock result" ... >>> print some_function() hello 

值得注意的是,mock.patch 把模拟的效果限制在 with 做用域的范围内,因此 with 做用域以外的 some_function 的返回值依旧为 hello。python2.7


Setting Return Values and Attributes

mock 一样可方便的模拟返回值和 attributes,例如模拟一个对象的返回值,ide

>>> value_mock = mock.Mock() >>> value_mock.return_value = 3 >>> value_mock() 3 

模拟一个方法的返回值:

>>> method_value_mock = mock.Mock() >>> method_value_mock.method.return_value = 3 >>> method_value_mock.method() 3 

模拟对象的 attribute:

>>> attr_mock = mock.Mock() >>> attr_mock.x = 3 >>> attr_mock.x 3 

参数 side_effect

side_effect 是一个很是有用的参数,大大提升了 mock 返回值的灵活性,它能够是一个异常、函数或者可迭代对象。例如返回一个异常:

>>> except_mock = mock.Mock(side_effect=Exception('Boom!')) >>> except_mock() Traceback (most recent call last): ... Exception: Boom! 

当 side_effect 为迭代对象时,样例以下:

>>> iter_mock = mock.Mock(side_effect=[1, 2, 3]) >>> iter_mock() 1 >>> iter_mock() 2 >>> iter_mock() 3 >>> iter_mock() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Python/2.7/site-packages/mock/mock.py", line 1062, in __call__ return _mock_self._mock_call(*args, **kwargs) File "/Library/Python/2.7/site-packages/mock/mock.py", line 1121, in _mock_call result = next(effect) File "/Library/Python/2.7/site-packages/mock/mock.py", line 127, in next return _next(obj) StopIteration 

单 side_effect 为函数时,样例以下:

>>> def side_effect(value): ... return value ... >>> >>> side_effect_mock = mock.Mock(side_effect=side_effect) >>> side_effect_mock(1) 1 >>> side_effect_mock("hello world!") 'hello world!'
相关文章
相关标签/搜索