=========== pytest-mock =========== This plugin installs a ``mocker`` fixture which is a thin-wrapper around the patching API provided by the excellent `mock `_ package, but with the benefit of not having to worry about undoing patches at the end of a test: .. code-block:: python def test_unix_fs(mocker): mocker.patch('os.remove') UnixFS.rm('file') os.remove.assert_called_once_with('file') .. Using PNG badges because PyPI doesn't support SVG |python| |version| |downloads| |ci| |coverage| .. |version| image:: http://img.shields.io/pypi/v/pytest-mock.png :target: https://pypi.python.org/pypi/pytest-mock .. |downloads| image:: http://img.shields.io/pypi/dm/pytest-mock.png :target: https://pypi.python.org/pypi/pytest-mock .. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.png :target: https://travis-ci.org/pytest-dev/pytest-mock .. |coverage| image:: http://img.shields.io/coveralls/pytest-dev/pytest-mock.png :target: https://coveralls.io/r/pytest-dev/pytest-mock .. |python| image:: https://pypip.in/py_versions/pytest-mock/badge.png :target: https://pypi.python.org/pypi/pytest-mock/ :alt: Supported Python versions Usage ===== The ``mocker`` fixture has the same API as `mock.patch `_, supporting the same arguments: .. code-block:: python def test_foo(mocker): # all valid calls mocker.patch('os.remove') mocker.patch.object(os, 'listdir', autospec=True) mocked_isfile = mocker.patch('os.path.isfile') The supported methods are: * ``mocker.patch``: see http://www.voidspace.org.uk/python/mock/patch.html#patch. * ``mocker.patch.object``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-object. * ``mocker.patch.multiple``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-multiple. * ``mocker.patch.dict``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-dict. * ``mocker.stopall()``: stops all active patches at this point. Note that, although mocker's API is intentionally the same as ``mock.patch``'s, its uses as context managers and function decorators are **not** supported. The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary. Indeed, trying to use the functionality in ``mocker`` in this manner can lead to non-intuitive errors: .. code-block:: python def test_context_manager(mocker): a = A() with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): assert a.doIt() == True .. code-block:: console ================================== FAILURES =================================== ____________________________ test_context_manager _____________________________ in test_context_manager with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): E AttributeError: __exit__ You can also access ``Mock`` and ``MagicMock`` directly using from ``mocker`` fixture: .. code-block:: python def test_feature(mocker): ret = [mocker.Mock(return_value=True), mocker.Mock(return_value=True)] mocker.patch('mylib.func', side_effect=ret) *New in version 0.5* Spy --- *New in version 0.6* The spy acts exactly like the original method in all cases, except it allows use of `mock` features with it, like retrieving call count. From version 0.7 onward it also works for class and static methods. Originally it was only safe to use with instance methods. .. code-block:: python def test_spy(mocker): class Foo(object): def bar(self): return 42 foo = Foo() mocker.spy(foo, 'bar') assert foo.bar() == 42 assert foo.bar.call_count == 1 Stub ---- *New in version 0.6* The stub is a mock object that accepts any arguments and is useful to test callbacks, for instance. .. code-block:: python def test_stub(mocker): def foo(on_something): on_something('foo', 'bar') stub = mocker.stub() foo(stub) stub.assert_called_once_with('foo', 'bar') Note ---- Prior to version ``0.4.0``, the ``mocker`` fixture was named ``mock``. This was changed because naming the fixture ``mock`` conflicts with the actual ``mock`` module, which made using it awkward when access to both the module and the plugin were required within a test. The old fixture ``mock`` still works, but its use is discouraged and will be removed in version ``1.0``. Requirements ============ * Python 2.6+, Python 3.2+ * pytest * mock (for Python < 3.3) Install ======= Install using `pip `_: .. code-block:: console $ pip install pytest-mock Changelog ========= Please consult `releases `_. Why bother with a plugin? ========================= There are a number of different ``patch`` usages in the standard ``mock`` API, but IMHO they don't scale very well when you have more than one or two patches to apply. It may lead to an excessive nesting of ``with`` statements, breaking the flow of the test: .. code-block:: python import mock def test_unix_fs(): with mock.patch('os.remove'): UnixFS.rm('file') os.remove.assert_called_once_with('file') with mock.patch('os.listdir'): assert UnixFS.ls('dir') == expected # ... with mock.patch('shutil.copy'): UnixFS.cp('src', 'dst') # ... One can use ``patch`` as a decorator to improve the flow of the test: .. code-block:: python @mock.patch('os.remove') @mock.patch('os.listdir') @mock.patch('shutil.copy') def test_unix_fs(mocked_copy, mocked_listdir, mocked_remove): UnixFS.rm('file') os.remove.assert_called_once_with('file') assert UnixFS.ls('dir') == expected # ... UnixFS.cp('src', 'dst') # ... But this poses a few disadvantages: - test functions must receive the mock objects as parameter, even if you don't plan to access them directly; also, order depends on the order of the decorated ``patch`` functions; - receiving the mocks as parameters doesn't mix nicely with pytest's approach of naming fixtures as parameters, or ``pytest.mark.parametrize``; - you can't easily undo the mocking during the test execution;