Metadata-Version: 2.1 Name: pytest-mock Version: 2.0.0 Summary: Thin-wrapper around the mock package for easier use with py.test Home-page: https://github.com/pytest-dev/pytest-mock/ Author: Bruno Oliveira Author-email: nicoddemus@gmail.com License: MIT Keywords: pytest mock Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Framework :: Pytest Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Topic :: Software Development :: Testing Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* Requires-Dist: pytest (>=2.7) Requires-Dist: mock ; python_version < "3.0" Provides-Extra: dev Requires-Dist: pre-commit ; extra == 'dev' Requires-Dist: tox ; extra == 'dev' =========== pytest-mock =========== This plugin provides a ``mocker`` fixture which is a thin-wrapper around the patching API provided by the `mock package `_: .. code-block:: python import os class UnixFS: @staticmethod def rm(filename): os.remove(filename) def test_unix_fs(mocker): mocker.patch('os.remove') UnixFS.rm('file') os.remove.assert_called_once_with('file') Besides undoing the mocking automatically after the end of the test, it also provides other nice utilities such as ``spy`` and ``stub``, and uses pytest introspection when comparing calls. |python| |version| |anaconda| |ci| |coverage| |black| .. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg :target: https://pypi.python.org/pypi/pytest-mock .. |anaconda| image:: https://img.shields.io/conda/vn/conda-forge/pytest-mock.svg :target: https://anaconda.org/conda-forge/pytest-mock .. |ci| image:: https://github.com/pytest-dev/pytest-mock/workflows/build/badge.svg :target: https://github.com/pytest-dev/pytest-mock/actions .. |coverage| image:: https://coveralls.io/repos/github/pytest-dev/pytest-mock/badge.svg?branch=master :target: https://coveralls.io/github/pytest-dev/pytest-mock?branch=master .. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg :target: https://pypi.python.org/pypi/pytest-mock/ .. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/ambv/black `Professionally supported pytest-mock is now available `_ 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 `_ * `mocker.patch.object `_ * `mocker.patch.multiple `_ * `mocker.patch.dict `_ * `mocker.stopall `_ * ``mocker.resetall()``: calls `reset_mock() `_ in all mocked objects up to this point. Also, as a convenience, these names from the ``mock`` module are accessible directly from ``mocker``: * `Mock `_ * `MagicMock `_ * `PropertyMock `_ * `ANY `_ * `DEFAULT `_ *(Version 1.4)* * `call `_ *(Version 1.1)* * `sentinel `_ *(Version 1.2)* * `mock_open `_ Spy --- The ``mocker.spy`` object acts exactly like the original method in all cases, except the spy also tracks method calls, return values and exceptions raised. .. code-block:: python def test_spy(mocker): class Foo(object): def bar(self, v): return v * 2 foo = Foo() spy = mocker.spy(foo, 'bar') assert foo.bar(21) == 42 spy.assert_called_once_with(21) assert spy.spy_return == 42 The object returned by ``mocker.spy`` is a ``MagicMock`` object, so all standard checking functions are available (like ``assert_called_once_with`` in the example above). In addition, spy objects contain two extra attributes: * ``spy_return``: contains the returned value of the spied function. * ``spy_exception``: contain the last exception value raised by the spied function/method when it was last called, or ``None`` if no exception was raised. ``mocker.spy`` also works for class and static methods. .. note:: In versions earlier than ``2.0``, the attributes were called ``return_value`` and ``side_effect`` respectively, but due to incompatibilities with ``unittest.mock`` they had to be renamed (see `#175`_ for details). .. _#175: https://github.com/pytest-dev/pytest-mock/issues/175 Stub ---- The stub is a mock object that accepts any arguments and is useful to test callbacks. It may receive an optional name that is shown in its ``repr``, useful for debugging. .. code-block:: python def test_stub(mocker): def foo(on_something): on_something('foo', 'bar') stub = mocker.stub(name='on_something_stub') foo(stub) stub.assert_called_once_with('foo', 'bar') Improved reporting of mock call assertion errors ------------------------------------------------ This plugin monkeypatches the mock library to improve pytest output for failures of mock call assertions like ``Mock.assert_called_with()`` by hiding internal traceback entries from the ``mock`` module. It also adds introspection information on differing call arguments when calling the helper methods. This features catches `AssertionError` raised in the method, and uses py.test's own `advanced assertions`_ to return a better diff:: mocker = def test(mocker): m = mocker.Mock() m('fo') > m.assert_called_once_with('', bar=4) E AssertionError: Expected call: mock('', bar=4) E Actual call: mock('fo') E E pytest introspection follows: E E Args: E assert ('fo',) == ('',) E At index 0 diff: 'fo' != '' E Use -v to get the full diff E Kwargs: E assert {} == {'bar': 4} E Right contains more items: E {'bar': 4} E Use -v to get the full diff test_foo.py:6: AssertionError ========================== 1 failed in 0.03 seconds =========================== This is useful when asserting mock calls with many/nested arguments and trying to quickly see the difference. This feature is probably safe, but if you encounter any problems it can be disabled in your ``pytest.ini`` file: .. code-block:: ini [pytest] mock_traceback_monkeypatch = false Note that this feature is automatically disabled with the ``--tb=native`` option. The underlying mechanism used to suppress traceback entries from ``mock`` module does not work with that option anyway plus it generates confusing messages on Python 3.5 due to exception chaining .. _advanced assertions: http://pytest.org/latest/assert.html Use standalone "mock" package ----------------------------- *New in version 1.4.0.* Python 3 users might want to use a newest version of the ``mock`` package as published on PyPI than the one that comes with the Python distribution. .. code-block:: ini [pytest] mock_use_standalone_module = true This will force the plugin to import ``mock`` instead of the ``unittest.mock`` module bundled with Python 3.4+. Note that this option is only used in Python 3+, as Python 2 users only have the option to use the ``mock`` package from PyPI anyway. Note about usage as context manager ----------------------------------- Although mocker's API is intentionally the same as ``mock.patch``'s, its use as context manager and function decorator is **not** supported through the fixture: .. code-block:: python def test_context_manager(mocker): a = A() with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): # DO NOT DO THIS assert a.doIt() == True The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary. Requirements ============ * Python 2.7, Python 3.4+ * pytest * mock (for Python 2) Install ======= Install using `pip `_: .. code-block:: console $ pip install pytest-mock Changelog ========= Please consult the `changelog page`_. .. _changelog page: https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst 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; An alternative is to use ``contextlib.ExitStack`` to stack the context managers in a single level of indentation to improve the flow of the test: .. code-block:: python import contextlib import mock def test_unix_fs(): with contextlib.ExitStack() as stack: stack.enter_context(mock.patch('os.remove')) UnixFS.rm('file') os.remove.assert_called_once_with('file') stack.enter_context(mock.patch('os.listdir')) assert UnixFS.ls('dir') == expected # ... stack.enter_context(mock.patch('shutil.copy')) UnixFS.cp('src', 'dst') # ... But this is arguably a little more complex than using ``pytest-mock``. Contributing ============ Contributions are welcome! After cloning the repository, create a virtual env and install ``pytest-mock`` in editable mode with ``dev`` extras: .. code-block:: console $ pip install --editable .[dev] $ pre-commit install Tests are run with ``tox``, you can run the baseline environments before submitting a PR: .. code-block:: console $ tox -e py27,py36,linting Style checks and formatting are done automatically during commit courtesy of `pre-commit `_. License ======= Distributed under the terms of the `MIT`_ license. Security contact information ============================ To report a security vulnerability, please use the `Tidelift security contact `__. Tidelift will coordinate the fix and disclosure. .. _MIT: https://github.com/pytest-dev/pytest-mock/blob/master/LICENSE