Skip to content

Commit 0467f9a

Browse files
authored
Merge pull request #290 from nicoddemus/readthedocs
2 parents 7116858 + b6abf61 commit 0467f9a

File tree

12 files changed

+477
-345
lines changed

12 files changed

+477
-345
lines changed

CHANGELOG.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
Releases
2+
========
3+
4+
15
3.7.0 (2022-01-28)
26
------------------
37

@@ -414,8 +418,7 @@ Breaking Changes
414418
option.
415419
Thanks `@asfaltboy`_ for the PR (`#36`_).
416420

417-
* ``mocker.stub()`` now allows passing in the name for the constructed `Mock
418-
<https://docs.python.org/3/library/unittest.mock.html#the-mock-class>`_
421+
* ``mocker.stub()`` now allows passing in the name for the constructed ``Mock``
419422
object instead of having to set it using the internal ``_mock_name`` attribute
420423
directly. This is useful for debugging as the name is used in the mock's
421424
``repr`` string as well as related assertion failure messages.

README.rst

Lines changed: 6 additions & 343 deletions
Original file line numberDiff line numberDiff line change
@@ -48,359 +48,22 @@ comparing calls.
4848
.. |pre-commit| image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest-mock/master.svg
4949
:target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest-mock/master
5050

51-
`Professionally supported pytest-mock is now available <https://tidelift.com/subscription/pkg/pypi-pytest_mock?utm_source=pypi-pytest-mock&utm_medium=referral&utm_campaign=readme>`_
51+
.. image:: https://readthedocs.org/projects/pytest-mock/badge/?version=latest
52+
:target: https://pytest-mock.readthedocs.io/en/latest/?badge=latest
5253

53-
Usage
54-
=====
5554

56-
The ``mocker`` fixture has the same API as
57-
`mock.patch <https://docs.python.org/3/library/unittest.mock.html#patch>`_,
58-
supporting the same arguments:
55+
`Professionally supported pytest-mock is available <https://tidelift.com/subscription/pkg/pypi-pytest_mock?utm_source=pypi-pytest-mock&utm_medium=referral&utm_campaign=readme>`_.
5956

60-
.. code-block:: python
61-
62-
def test_foo(mocker):
63-
# all valid calls
64-
mocker.patch('os.remove')
65-
mocker.patch.object(os, 'listdir', autospec=True)
66-
mocked_isfile = mocker.patch('os.path.isfile')
67-
68-
The supported methods are:
69-
70-
* `mocker.patch <https://docs.python.org/3/library/unittest.mock.html#patch>`_
71-
* `mocker.patch.object <https://docs.python.org/3/library/unittest.mock.html#patch-object>`_
72-
* `mocker.patch.multiple <https://docs.python.org/3/library/unittest.mock.html#patch-multiple>`_
73-
* `mocker.patch.dict <https://docs.python.org/3/library/unittest.mock.html#patch-dict>`_
74-
* `mocker.stopall <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch.stopall>`_
75-
* ``mocker.resetall()``: calls `reset_mock() <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.reset_mock>`_ in all mocked objects up to this point.
76-
77-
Also, as a convenience, these names from the ``mock`` module are accessible directly from ``mocker``:
78-
79-
* `Mock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock>`_
80-
* `MagicMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock>`_
81-
* `PropertyMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.PropertyMock>`_
82-
* `ANY <https://docs.python.org/3/library/unittest.mock.html#any>`_
83-
* `DEFAULT <https://docs.python.org/3/library/unittest.mock.html#default>`_ *(Version 1.4)*
84-
* `call <https://docs.python.org/3/library/unittest.mock.html#call>`_ *(Version 1.1)*
85-
* `sentinel <https://docs.python.org/3/library/unittest.mock.html#sentinel>`_ *(Version 1.2)*
86-
* `mock_open <https://docs.python.org/3/library/unittest.mock.html#mock-open>`_
87-
* `seal <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.seal>`_ *(Version 3.4)*
88-
89-
It is also possible to use mocking functionality from fixtures of other scopes using
90-
the appropriate mock fixture:
91-
92-
* ``class_mocker``
93-
* ``module_mocker``
94-
* ``package_mocker``
95-
* ``session_mocker``
96-
97-
Type Annotations
98-
----------------
99-
100-
*New in version 3.3.0.*
101-
102-
``pytest-mock`` is fully type annotated, letting users use static type checkers to
103-
test their code.
104-
105-
The ``mocker`` fixture returns ``pytest_mock.MockerFixture`` which can be used
106-
to annotate test functions:
107-
108-
.. code-block:: python
109-
110-
from pytest_mock import MockerFixture
111-
112-
def test_foo(mocker: MockerFixture) -> None:
113-
...
114-
115-
The type annotations have been checked with ``mypy``, which is the only
116-
type checker supported at the moment; other type-checkers might work
117-
but are not currently tested.
118-
119-
Spy
120-
---
121-
122-
The ``mocker.spy`` object acts exactly like the original method in all cases, except the spy
123-
also tracks function/method calls, return values and exceptions raised.
124-
125-
.. code-block:: python
126-
127-
def test_spy_method(mocker):
128-
class Foo(object):
129-
def bar(self, v):
130-
return v * 2
131-
132-
foo = Foo()
133-
spy = mocker.spy(foo, 'bar')
134-
assert foo.bar(21) == 42
135-
136-
spy.assert_called_once_with(21)
137-
assert spy.spy_return == 42
138-
139-
def test_spy_function(mocker):
140-
# mymodule declares `myfunction` which just returns 42
141-
import mymodule
142-
143-
spy = mocker.spy(mymodule, "myfunction")
144-
assert mymodule.myfunction() == 42
145-
assert spy.call_count == 1
146-
assert spy.spy_return == 42
147-
148-
The object returned by ``mocker.spy`` is a ``MagicMock`` object, so all standard checking functions
149-
are available (like ``assert_called_once_with`` or ``call_count`` in the examples above).
150-
151-
In addition, spy objects contain two extra attributes:
152-
153-
* ``spy_return``: contains the returned value of the spied function.
154-
* ``spy_exception``: contain the last exception value raised by the spied function/method when
155-
it was last called, or ``None`` if no exception was raised.
156-
157-
Besides functions and normal methods, ``mocker.spy`` also works for class and static methods.
158-
159-
As of version 3.0.0, ``mocker.spy`` also works with ``async def`` functions.
160-
161-
.. note::
162-
163-
In versions earlier than ``2.0``, the attributes were called ``return_value`` and
164-
``side_effect`` respectively, but due to incompatibilities with ``unittest.mock``
165-
they had to be renamed (see `#175`_ for details).
166-
167-
.. _#175: https://github.com/pytest-dev/pytest-mock/issues/175
168-
169-
Stub
170-
----
171-
172-
The stub is a mock object that accepts any arguments and is useful to test callbacks.
173-
It may receive an optional name that is shown in its ``repr``, useful for debugging.
174-
175-
.. code-block:: python
176-
177-
def test_stub(mocker):
178-
def foo(on_something):
179-
on_something('foo', 'bar')
180-
181-
stub = mocker.stub(name='on_something_stub')
182-
183-
foo(stub)
184-
stub.assert_called_once_with('foo', 'bar')
185-
186-
187-
Improved reporting of mock call assertion errors
188-
------------------------------------------------
189-
190-
This plugin monkeypatches the mock library to improve pytest output for failures
191-
of mock call assertions like ``Mock.assert_called_with()`` by hiding internal traceback
192-
entries from the ``mock`` module.
193-
194-
It also adds introspection information on differing call arguments when
195-
calling the helper methods. This features catches `AssertionError` raised in
196-
the method, and uses pytest's own `advanced assertions`_ to return a better
197-
diff::
198-
199-
200-
mocker = <pytest_mock.MockerFixture object at 0x0381E2D0>
201-
202-
def test(mocker):
203-
m = mocker.Mock()
204-
m('fo')
205-
> m.assert_called_once_with('', bar=4)
206-
E AssertionError: Expected call: mock('', bar=4)
207-
E Actual call: mock('fo')
208-
E
209-
E pytest introspection follows:
210-
E
211-
E Args:
212-
E assert ('fo',) == ('',)
213-
E At index 0 diff: 'fo' != ''
214-
E Use -v to get the full diff
215-
E Kwargs:
216-
E assert {} == {'bar': 4}
217-
E Right contains more items:
218-
E {'bar': 4}
219-
E Use -v to get the full diff
220-
221-
222-
test_foo.py:6: AssertionError
223-
========================== 1 failed in 0.03 seconds ===========================
224-
225-
226-
This is useful when asserting mock calls with many/nested arguments and trying
227-
to quickly see the difference.
228-
229-
This feature is probably safe, but if you encounter any problems it can be disabled in
230-
your ``pytest.ini`` file:
231-
232-
.. code-block:: ini
233-
234-
[pytest]
235-
mock_traceback_monkeypatch = false
236-
237-
Note that this feature is automatically disabled with the ``--tb=native`` option. The underlying
238-
mechanism used to suppress traceback entries from ``mock`` module does not work with that option
239-
anyway plus it generates confusing messages on Python 3.5 due to exception chaining
240-
241-
.. _advanced assertions: http://docs.pytest.org/en/stable/assert.html
24257

58+
Documentation
59+
=============
24360

244-
Use standalone "mock" package
245-
-----------------------------
246-
247-
*New in version 1.4.0.*
248-
249-
Python 3 users might want to use a newest version of the ``mock`` package as published on PyPI
250-
than the one that comes with the Python distribution.
251-
252-
.. code-block:: ini
253-
254-
[pytest]
255-
mock_use_standalone_module = true
256-
257-
This will force the plugin to import ``mock`` instead of the ``unittest.mock`` module bundled with
258-
Python 3.4+. Note that this option is only used in Python 3+, as Python 2 users only have the option
259-
to use the ``mock`` package from PyPI anyway.
260-
261-
Note about usage as context manager
262-
-----------------------------------
263-
264-
Although mocker's API is intentionally the same as ``mock.patch``'s, its use
265-
as context manager and function decorator is **not** supported through the
266-
fixture:
267-
268-
.. code-block:: python
269-
270-
def test_context_manager(mocker):
271-
a = A()
272-
with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): # DO NOT DO THIS
273-
assert a.doIt() == True
274-
275-
The purpose of this plugin is to make the use of context managers and
276-
function decorators for mocking unnecessary, so it will emit a warning when used as such.
277-
278-
If you really intend to mock a context manager, ``mocker.patch.context_manager`` exists
279-
which won't issue the above warning.
280-
281-
282-
Install
283-
=======
284-
285-
Install using `pip <http://pip-installer.org/>`_:
286-
287-
.. code-block:: console
288-
289-
$ pip install pytest-mock
290-
291-
Changelog
292-
=========
293-
294-
Please consult the `changelog page`_.
295-
296-
.. _changelog page: https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst
297-
298-
Why bother with a plugin?
299-
=========================
300-
301-
There are a number of different ``patch`` usages in the standard ``mock`` API,
302-
but IMHO they don't scale very well when you have more than one or two
303-
patches to apply.
304-
305-
It may lead to an excessive nesting of ``with`` statements, breaking the flow
306-
of the test:
307-
308-
.. code-block:: python
309-
310-
import mock
311-
312-
def test_unix_fs():
313-
with mock.patch('os.remove'):
314-
UnixFS.rm('file')
315-
os.remove.assert_called_once_with('file')
316-
317-
with mock.patch('os.listdir'):
318-
assert UnixFS.ls('dir') == expected
319-
# ...
320-
321-
with mock.patch('shutil.copy'):
322-
UnixFS.cp('src', 'dst')
323-
# ...
324-
325-
326-
One can use ``patch`` as a decorator to improve the flow of the test:
327-
328-
.. code-block:: python
329-
330-
@mock.patch('os.remove')
331-
@mock.patch('os.listdir')
332-
@mock.patch('shutil.copy')
333-
def test_unix_fs(mocked_copy, mocked_listdir, mocked_remove):
334-
UnixFS.rm('file')
335-
os.remove.assert_called_once_with('file')
336-
337-
assert UnixFS.ls('dir') == expected
338-
# ...
339-
340-
UnixFS.cp('src', 'dst')
341-
# ...
342-
343-
But this poses a few disadvantages:
344-
345-
- test functions must receive the mock objects as parameter, even if you don't plan to
346-
access them directly; also, order depends on the order of the decorated ``patch``
347-
functions;
348-
- receiving the mocks as parameters doesn't mix nicely with pytest's approach of
349-
naming fixtures as parameters, or ``pytest.mark.parametrize``;
350-
- you can't easily undo the mocking during the test execution;
351-
352-
An alternative is to use ``contextlib.ExitStack`` to stack the context managers in a single level of indentation
353-
to improve the flow of the test:
354-
355-
.. code-block:: python
356-
357-
import contextlib
358-
import mock
359-
360-
def test_unix_fs():
361-
with contextlib.ExitStack() as stack:
362-
stack.enter_context(mock.patch('os.remove'))
363-
UnixFS.rm('file')
364-
os.remove.assert_called_once_with('file')
365-
366-
stack.enter_context(mock.patch('os.listdir'))
367-
assert UnixFS.ls('dir') == expected
368-
# ...
369-
370-
stack.enter_context(mock.patch('shutil.copy'))
371-
UnixFS.cp('src', 'dst')
372-
# ...
373-
374-
But this is arguably a little more complex than using ``pytest-mock``.
375-
376-
Contributing
377-
============
378-
379-
Contributions are welcome! After cloning the repository, create a virtual env
380-
and install ``pytest-mock`` in editable mode with ``dev`` extras:
381-
382-
.. code-block:: console
383-
384-
$ pip install --editable .[dev]
385-
$ pre-commit install
386-
387-
Tests are run with ``tox``, you can run the baseline environments before submitting a PR:
388-
389-
.. code-block:: console
390-
391-
$ tox -e py38,linting
392-
393-
Style checks and formatting are done automatically during commit courtesy of
394-
`pre-commit <https://pre-commit.com>`_.
61+
For full documentation, please see https://pytest-mock.readthedocs.io/en/latest.
39562

39663
License
39764
=======
39865

39966
Distributed under the terms of the `MIT`_ license.
40067

401-
Security contact information
402-
============================
403-
404-
To report a security vulnerability, please use the `Tidelift security contact <https://tidelift.com/security>`__. Tidelift will coordinate the fix and disclosure.
40568

40669
.. _MIT: https://github.com/pytest-dev/pytest-mock/blob/master/LICENSE

0 commit comments

Comments
 (0)