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!'
相關文章
相關標籤/搜索