Skip to content

bpo-27200: fix unittest.mock doctests. #821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 73 additions & 8 deletions Doc/library/unittest.mock-examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

.. versionadded:: 3.3

.. testsetup::

import unittest
from unittest.mock import MagicMock, sentinel, patch


.. _getting-started:

Expand All @@ -23,6 +28,9 @@ Common uses for :class:`Mock` objects include:
You might want to replace a method on an object to check that
it is called with the correct arguments by another part of the system:

.. doctest::
:options: +SKIP

>>> real = SomeClass()
>>> real.method = MagicMock(name='method')
>>> real.method(3, 4, 5, key='value')
Expand Down Expand Up @@ -77,6 +85,7 @@ an object then it calls ``close`` on it.
So to test it we need to pass in an object with a ``close`` method and check
that it was called correctly.

>>> from unittest.mock import Mock
>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
Expand All @@ -101,6 +110,9 @@ and calls a method on it. The call to :func:`patch` replaces the class ``Foo`` w
mock. The ``Foo`` instance is the result of calling the mock, so it is configured
by modifying the mock :attr:`~Mock.return_value`.

.. doctest::
:options: +SKIP

>>> def some_function():
... instance = module.Foo()
... return instance.method()
Expand Down Expand Up @@ -149,6 +161,7 @@ that they were made in the right order and with no additional calls:
You use the :data:`call` object to construct lists for comparing with
``mock_calls``:

>>> from unittest.mock import call
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
Expand Down Expand Up @@ -271,6 +284,9 @@ attribute error. If you change the implementation of your specification, then
tests that use that class will start failing immediately without you having to
instantiate the class in those tests.

.. doctest::
:options: +SKIP

>>> mock = Mock(spec=SomeClass)
>>> mock.old_method()
Traceback (most recent call last):
Expand Down Expand Up @@ -323,6 +339,9 @@ with.

``patch.object``:

.. doctest::
:options: +SKIP

>>> original = SomeClass.attribute
>>> @patch.object(SomeClass, 'attribute', sentinel.attribute)
... def test():
Expand All @@ -341,6 +360,9 @@ with.
If you are patching a module (including :mod:`builtins`) then use :func:`patch`
instead of :func:`patch.object`:

.. doctest::
:options: +SKIP

>>> mock = MagicMock(return_value=sentinel.file_handle)
>>> with patch('builtins.open', mock):
... handle = open('filename', 'r')
Expand All @@ -350,6 +372,9 @@ instead of :func:`patch.object`:

The module name can be 'dotted', in the form ``package.module`` if needed:

.. doctest::
:options: +SKIP

>>> @patch('package.module.ClassName.attribute', sentinel.attribute)
... def test():
... from package.module import ClassName
Expand All @@ -359,6 +384,9 @@ The module name can be 'dotted', in the form ``package.module`` if needed:

A nice pattern is to actually decorate test methods themselves:

.. doctest::
:options: +SKIP

>>> class MyTest(unittest.TestCase):
... @patch.object(SomeClass, 'attribute', sentinel.attribute)
... def test_something(self):
Expand All @@ -372,6 +400,9 @@ If you want to patch with a Mock, you can use :func:`patch` with only one argume
(or :func:`patch.object` with two arguments). The mock will be created for you and
passed into the test function / method:

.. doctest::
:options: +SKIP

>>> class MyTest(unittest.TestCase):
... @patch.object(SomeClass, 'static_method')
... def test_something(self, mock_method):
Expand All @@ -389,7 +420,7 @@ You can stack up multiple patch decorators using this pattern:
... self.assertIs(package.module.ClassName1, MockClass1)
... self.assertIs(package.module.ClassName2, MockClass2)
...
>>> MyTest('test_something').test_something()
>>> MyTest('test_something').test_something() # doctest: +SKIP

When you nest patch decorators the mocks are passed in to the decorated
function in the same order they applied (the normal *python* order that
Expand Down Expand Up @@ -460,6 +491,9 @@ testable way in the first place...

So, suppose we have some code that looks a little bit like this:

.. doctest::
:options: +SKIP

>>> class Something:
... def __init__(self):
... self.backend = BackendProvider()
Expand Down Expand Up @@ -487,6 +521,9 @@ response object for it. To set the response as the return value for that final
We can do that in a slightly nicer way using the :meth:`~Mock.configure_mock`
method to directly set the return value for us:

.. doctest::
:options: +SKIP

>>> something = Something()
>>> mock_response = Mock(spec=open)
>>> mock_backend = Mock()
Expand All @@ -496,6 +533,9 @@ method to directly set the return value for us:
With these we monkey patch the "mock backend" in place and can make the real
call:

.. doctest::
:options: +SKIP

>>> something.backend = mock_backend
>>> something.method()

Expand All @@ -504,6 +544,9 @@ assert. A chained call is several calls in one line of code, so there will be
several entries in ``mock_calls``. We can use :meth:`call.call_list` to create
this list of calls for us:

.. doctest::
:options: +SKIP

>>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call()
>>> call_list = chained.call_list()
>>> assert mock_backend.mock_calls == call_list
Expand All @@ -527,6 +570,9 @@ attribute on the mock date class is then set to a lambda function that returns
a real date. When the mock date class is called a real date will be
constructed and returned by ``side_effect``.

.. doctest::
:options: +SKIP

>>> from datetime import date
>>> with patch('mymodule.date') as mock_date:
... mock_date.today.return_value = date(2010, 10, 8)
Expand Down Expand Up @@ -602,6 +648,9 @@ various forms) as a class decorator. This applies the patches to all test
methods on the class. A test method is identified by methods whose names start
with ``test``:

.. doctest::
:options: +SKIP

>>> @patch('mymodule.SomeClass')
... class MyTest(TestCase):
...
Expand All @@ -622,7 +671,7 @@ with ``test``:
An alternative way of managing patches is to use the :ref:`start-and-stop`.
These allow you to move the patching into your ``setUp`` and ``tearDown`` methods.

>>> class MyTest(TestCase):
>>> class MyTest(unittest.TestCase):
... def setUp(self):
... self.patcher = patch('mymodule.foo')
... self.mock_foo = self.patcher.start()
Expand All @@ -633,14 +682,14 @@ These allow you to move the patching into your ``setUp`` and ``tearDown`` method
... def tearDown(self):
... self.patcher.stop()
...
>>> MyTest('test_foo').run()
>>> MyTest('test_foo').run() # doctest: +SKIP

If you use this technique you must ensure that the patching is "undone" by
calling ``stop``. This can be fiddlier than you might think, because if an
exception is raised in the setUp then tearDown is not called.
:meth:`unittest.TestCase.addCleanup` makes this easier:

>>> class MyTest(TestCase):
>>> class MyTest(unittest.TestCase):
... def setUp(self):
... patcher = patch('mymodule.foo')
... self.addCleanup(patcher.stop)
Expand All @@ -649,7 +698,7 @@ exception is raised in the setUp then tearDown is not called.
... def test_foo(self):
... self.assertIs(mymodule.foo, self.mock_foo)
...
>>> MyTest('test_foo').run()
>>> MyTest('test_foo').run() # doctest: +SKIP


Mocking Unbound Methods
Expand Down Expand Up @@ -755,6 +804,9 @@ defined in 'mymodule'::
When we try to test that ``grob`` calls ``frob`` with the correct argument look
what happens:

.. doctest::
:options: +SKIP

>>> with patch('mymodule.frob') as mock_frob:
... val = {6}
... mymodule.grob(val)
Expand All @@ -779,6 +831,9 @@ example I'm using *another* mock to store the arguments so that I can use the
mock methods for doing the assertion. Again a helper function sets this up for
me.

.. doctest::
:options: +SKIP

>>> from copy import deepcopy
>>> from unittest.mock import Mock, patch, DEFAULT
>>> def copy_call_args(mock):
Expand Down Expand Up @@ -856,7 +911,10 @@ Using patch as a context manager is nice, but if you do multiple patches you
can end up with nested with statements indenting further and further to the
right:

>>> class MyTest(TestCase):
.. doctest::
:options: +SKIP

>>> class MyTest(unittest.TestCase):
...
... def test_foo(self):
... with patch('mymodule.Foo') as mock_foo:
Expand All @@ -875,7 +933,10 @@ achieve the same effect without the nested indentation. A simple helper
method, ``create_patch``, puts the patch in place and returns the created mock
for us:

>>> class MyTest(TestCase):
.. doctest::
:options: +SKIP

>>> class MyTest(unittest.TestCase):
...
... def create_patch(self, name):
... patcher = patch(name)
Expand Down Expand Up @@ -968,7 +1029,7 @@ mock methods and attributes:
[call('a'), call('c'), call('d'), call('b'), call('d')]
>>> mock.__setitem__.call_args_list
[call('b', 'fish'), call('d', 'eggs')]
>>> my_dict
>>> my_dict # doctest: +SKIP
{'a': 1, 'c': 3, 'b': 'fish', 'd': 'eggs'}


Expand Down Expand Up @@ -1070,6 +1131,7 @@ Here's an example that mocks out the 'fooble' module.
... fooble.blob()
...
<Mock name='mock.blob()' id='...'>
>>> import sys
>>> assert 'fooble' not in sys.modules
>>> mock.blob.assert_called_once_with()

Expand Down Expand Up @@ -1134,6 +1196,9 @@ If ``patch`` is creating, and putting in place, your mocks then you can attach
them to a manager mock using the :meth:`~Mock.attach_mock` method. After
attaching calls will be recorded in ``mock_calls`` of the manager.

.. doctest::
:options: +SKIP

>>> manager = MagicMock()
>>> with patch('mymodule.Class1') as MockClass1:
... with patch('mymodule.Class2') as MockClass2:
Expand Down
Loading