@@ -198,6 +198,23 @@ This will force the plugin to import ``mock`` instead of the ``unittest.mock`` m
198
198
Python 3.4+. Note that this option is only used in Python 3+, as Python 2 users only have the option
199
199
to use the ``mock `` package from PyPI anyway.
200
200
201
+ Note about usage as context manager
202
+ -----------------------------------
203
+
204
+ Although mocker's API is intentionally the same as ``mock.patch ``'s, its use
205
+ as context manager and function decorator is **not ** supported through the
206
+ fixture:
207
+
208
+ .. code-block :: python
209
+
210
+ def test_context_manager (mocker ):
211
+ a = A()
212
+ with mocker.patch.object(a, ' doIt' , return_value = True , autospec = True ): # DO NOT DO THIS
213
+ assert a.doIt() == True
214
+
215
+ The purpose of this plugin is to make the use of context managers and
216
+ function decorators for mocking unnecessary.
217
+
201
218
202
219
Requirements
203
220
============
@@ -277,47 +294,29 @@ But this poses a few disadvantages:
277
294
naming fixtures as parameters, or ``pytest.mark.parametrize ``;
278
295
- you can't easily undo the mocking during the test execution;
279
296
280
-
281
- **Note about usage as context manager **
282
-
283
- Although mocker's API is intentionally the same as ``mock.patch ``'s, its use
284
- as context manager and function decorator is **not ** supported through the
285
- fixture. The purpose of this plugin is to make the use of context managers and
286
- function decorators for mocking unnecessary. Indeed, trying to use the
287
- functionality in ``mocker `` in this manner can lead to non-intuitive errors:
297
+ An alternative is to use ``contextlib.ExitStack `` to stack the context managers in a single level of indentation
298
+ to improve the flow of the test:
288
299
289
300
.. code-block :: python
290
301
291
- def test_context_manager (mocker ):
292
- a = A()
293
- with mocker.patch.object(a, ' doIt' , return_value = True , autospec = True ):
294
- assert a.doIt() == True
295
-
296
- .. code-block :: console
297
-
298
- ================================== FAILURES ===================================
299
- ____________________________ test_context_manager _____________________________
300
- in test_context_manager
301
- with mocker.patch.object(a, 'doIt', return_value=True, autospec=True):
302
- E AttributeError: __exit__
303
-
304
- You can however use ``mocker.mock_module `` to access the underlying ``mock ``
305
- module, e.g. to return a context manager in a fixture that mocks something
306
- temporarily:
302
+ import contextlib
303
+ import mock
307
304
308
- .. code-block :: python
305
+ def test_unix_fs ():
306
+ with contextlib.ExitStack() as stack:
307
+ stack.enter_context(mock.patch(' os.remove' ))
308
+ UnixFS.rm(' file' )
309
+ os.remove.assert_called_once_with(' file' )
309
310
310
- @pytest.fixture
311
- def fixture_cm (mocker ):
312
- @contextlib.contextmanager
313
- def my_cm ():
314
- def mocked ():
315
- pass
311
+ stack.enter_context(mock.patch(' os.listdir' ))
312
+ assert UnixFS.ls(' dir' ) == expected
313
+ # ...
316
314
317
- with mocker.mock_module .patch.object(SomeClass, ' method ' , mocked):
318
- yield
319
- return my_cm
315
+ stack.enter_context(mock .patch( ' shutil.copy ' ))
316
+ UnixFS.cp( ' src ' , ' dst ' )
317
+ # ...
320
318
319
+ But this is arguably a little more complex than using ``pytest-mock ``.
321
320
322
321
Contributing
323
322
============
0 commit comments