Skip to content

Commit 449d3d0

Browse files
authored
Merge pull request #197 from tirkarthi/asyncmock-assert-diffs
2 parents e36a5f2 + 9b6e106 commit 449d3d0

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

CHANGELOG.rst

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
3.2.0 (2020-07-11)
2+
------------------
3+
4+
* `AsyncMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.AsyncMock>`__ is now exposed in ``mocker`` and supports provides assertion introspection similar to ``Mock`` objects.
5+
6+
Added by `@tirkarthi`_ in `#197`_.
7+
8+
.. _@tirkarthi: https://github.com/tirkarthi
9+
.. _#197: https://github.com/pytest-dev/pytest-mock/pull/197
10+
111
3.1.1 (2020-05-31)
212
------------------
313

src/pytest_mock/plugin.py

+57
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ def __init__(self, config):
4747
self.MagicMock = mock_module.MagicMock
4848
self.NonCallableMock = mock_module.NonCallableMock
4949
self.PropertyMock = mock_module.PropertyMock
50+
if hasattr(mock_module, "AsyncMock"):
51+
self.AsyncMock = mock_module.AsyncMock
5052
self.call = mock_module.call
5153
self.ANY = mock_module.ANY
5254
self.DEFAULT = mock_module.DEFAULT
@@ -275,6 +277,41 @@ def wrap_assert_called(*args, **kwargs):
275277
assert_wrapper(_mock_module_originals["assert_called"], *args, **kwargs)
276278

277279

280+
def wrap_assert_not_awaited(*args, **kwargs):
281+
__tracebackhide__ = True
282+
assert_wrapper(_mock_module_originals["assert_not_awaited"], *args, **kwargs)
283+
284+
285+
def wrap_assert_awaited_with(*args, **kwargs):
286+
__tracebackhide__ = True
287+
assert_wrapper(_mock_module_originals["assert_awaited_with"], *args, **kwargs)
288+
289+
290+
def wrap_assert_awaited_once(*args, **kwargs):
291+
__tracebackhide__ = True
292+
assert_wrapper(_mock_module_originals["assert_awaited_once"], *args, **kwargs)
293+
294+
295+
def wrap_assert_awaited_once_with(*args, **kwargs):
296+
__tracebackhide__ = True
297+
assert_wrapper(_mock_module_originals["assert_awaited_once_with"], *args, **kwargs)
298+
299+
300+
def wrap_assert_has_awaits(*args, **kwargs):
301+
__tracebackhide__ = True
302+
assert_wrapper(_mock_module_originals["assert_has_awaits"], *args, **kwargs)
303+
304+
305+
def wrap_assert_any_await(*args, **kwargs):
306+
__tracebackhide__ = True
307+
assert_wrapper(_mock_module_originals["assert_any_await"], *args, **kwargs)
308+
309+
310+
def wrap_assert_awaited(*args, **kwargs):
311+
__tracebackhide__ = True
312+
assert_wrapper(_mock_module_originals["assert_awaited"], *args, **kwargs)
313+
314+
278315
def wrap_assert_methods(config):
279316
"""
280317
Wrap assert methods of mock module so we can hide their traceback and
@@ -305,6 +342,26 @@ def wrap_assert_methods(config):
305342
patcher.start()
306343
_mock_module_patches.append(patcher)
307344

345+
if hasattr(mock_module, "AsyncMock"):
346+
async_wrappers = {
347+
"assert_awaited": wrap_assert_awaited,
348+
"assert_awaited_once": wrap_assert_awaited_once,
349+
"assert_awaited_with": wrap_assert_awaited_with,
350+
"assert_awaited_once_with": wrap_assert_awaited_once_with,
351+
"assert_any_await": wrap_assert_any_await,
352+
"assert_has_awaits": wrap_assert_has_awaits,
353+
"assert_not_awaited": wrap_assert_not_awaited,
354+
}
355+
for method, wrapper in async_wrappers.items():
356+
try:
357+
original = getattr(mock_module.AsyncMock, method)
358+
except AttributeError: # pragma: no cover
359+
continue
360+
_mock_module_originals[method] = original
361+
patcher = mock_module.patch.object(mock_module.AsyncMock, method, wrapper)
362+
patcher.start()
363+
_mock_module_patches.append(patcher)
364+
308365
if hasattr(config, "add_cleanup"):
309366
add_cleanup = config.add_cleanup
310367
else:

tests/test_pytest_mock.py

+37
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,43 @@ def test(mocker):
708708
result.stdout.fnmatch_lines(expected_lines)
709709

710710

711+
@pytest.mark.skipif(
712+
sys.version_info < (3, 8), reason="AsyncMock is present on 3.8 and above"
713+
)
714+
@pytest.mark.usefixtures("needs_assert_rewrite")
715+
def test_detailed_introspection_async(testdir):
716+
"""Check that the "mock_use_standalone" is being used.
717+
"""
718+
testdir.makepyfile(
719+
"""
720+
import pytest
721+
722+
@pytest.mark.asyncio
723+
async def test(mocker):
724+
m = mocker.AsyncMock()
725+
await m('fo')
726+
m.assert_awaited_once_with('', bar=4)
727+
"""
728+
)
729+
result = testdir.runpytest("-s")
730+
expected_lines = [
731+
"*AssertionError: expected await not found.",
732+
"*Expected: mock('', bar=4)",
733+
"*Actual: mock('fo')",
734+
"*pytest introspection follows:*",
735+
"*Args:",
736+
"*assert ('fo',) == ('',)",
737+
"*At index 0 diff: 'fo' != ''*",
738+
"*Use -v to get the full diff*",
739+
"*Kwargs:*",
740+
"*assert {} == {'bar': 4}*",
741+
"*Right contains* more item*",
742+
"*{'bar': 4}*",
743+
"*Use -v to get the full diff*",
744+
]
745+
result.stdout.fnmatch_lines(expected_lines)
746+
747+
711748
def test_missing_introspection(testdir):
712749
testdir.makepyfile(
713750
"""

0 commit comments

Comments
 (0)