======= Remarks ======= Type annotations ---------------- ``pytest-mock`` is fully type annotated, letting users use static type checkers to test their code. The ``mocker`` fixture returns ``pytest_mock.MockerFixture`` which can be used to annotate test functions: .. code-block:: python from pytest_mock import MockerFixture def test_foo(mocker: MockerFixture) -> None: ... The type annotations have been checked with ``mypy``, which is the only type checker supported at the moment; other type-checkers might work but are not currently tested. 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``.