Skip to content

Commit

Permalink
Merge pull request #197 from tirkarthi/asyncmock-assert-diffs
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoddemus committed Jul 11, 2020
2 parents e36a5f2 + 9b6e106 commit 449d3d0
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 0 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
3.2.0 (2020-07-11)
------------------

* `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.

Added by `@tirkarthi`_ in `#197`_.

.. _@tirkarthi: https://github.com/tirkarthi
.. _#197: https://github.com/pytest-dev/pytest-mock/pull/197

3.1.1 (2020-05-31)
------------------

Expand Down
57 changes: 57 additions & 0 deletions src/pytest_mock/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ def __init__(self, config):
self.MagicMock = mock_module.MagicMock
self.NonCallableMock = mock_module.NonCallableMock
self.PropertyMock = mock_module.PropertyMock
if hasattr(mock_module, "AsyncMock"):
self.AsyncMock = mock_module.AsyncMock
self.call = mock_module.call
self.ANY = mock_module.ANY
self.DEFAULT = mock_module.DEFAULT
Expand Down Expand Up @@ -275,6 +277,41 @@ def wrap_assert_called(*args, **kwargs):
assert_wrapper(_mock_module_originals["assert_called"], *args, **kwargs)


def wrap_assert_not_awaited(*args, **kwargs):
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_not_awaited"], *args, **kwargs)


def wrap_assert_awaited_with(*args, **kwargs):
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_awaited_with"], *args, **kwargs)


def wrap_assert_awaited_once(*args, **kwargs):
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_awaited_once"], *args, **kwargs)


def wrap_assert_awaited_once_with(*args, **kwargs):
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_awaited_once_with"], *args, **kwargs)


def wrap_assert_has_awaits(*args, **kwargs):
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_has_awaits"], *args, **kwargs)


def wrap_assert_any_await(*args, **kwargs):
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_any_await"], *args, **kwargs)


def wrap_assert_awaited(*args, **kwargs):
__tracebackhide__ = True
assert_wrapper(_mock_module_originals["assert_awaited"], *args, **kwargs)


def wrap_assert_methods(config):
"""
Wrap assert methods of mock module so we can hide their traceback and
Expand Down Expand Up @@ -305,6 +342,26 @@ def wrap_assert_methods(config):
patcher.start()
_mock_module_patches.append(patcher)

if hasattr(mock_module, "AsyncMock"):
async_wrappers = {
"assert_awaited": wrap_assert_awaited,
"assert_awaited_once": wrap_assert_awaited_once,
"assert_awaited_with": wrap_assert_awaited_with,
"assert_awaited_once_with": wrap_assert_awaited_once_with,
"assert_any_await": wrap_assert_any_await,
"assert_has_awaits": wrap_assert_has_awaits,
"assert_not_awaited": wrap_assert_not_awaited,
}
for method, wrapper in async_wrappers.items():
try:
original = getattr(mock_module.AsyncMock, method)
except AttributeError: # pragma: no cover
continue
_mock_module_originals[method] = original
patcher = mock_module.patch.object(mock_module.AsyncMock, method, wrapper)
patcher.start()
_mock_module_patches.append(patcher)

if hasattr(config, "add_cleanup"):
add_cleanup = config.add_cleanup
else:
Expand Down
37 changes: 37 additions & 0 deletions tests/test_pytest_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,43 @@ def test(mocker):
result.stdout.fnmatch_lines(expected_lines)


@pytest.mark.skipif(
sys.version_info < (3, 8), reason="AsyncMock is present on 3.8 and above"
)
@pytest.mark.usefixtures("needs_assert_rewrite")
def test_detailed_introspection_async(testdir):
"""Check that the "mock_use_standalone" is being used.
"""
testdir.makepyfile(
"""
import pytest
@pytest.mark.asyncio
async def test(mocker):
m = mocker.AsyncMock()
await m('fo')
m.assert_awaited_once_with('', bar=4)
"""
)
result = testdir.runpytest("-s")
expected_lines = [
"*AssertionError: expected await not found.",
"*Expected: mock('', bar=4)",
"*Actual: mock('fo')",
"*pytest introspection follows:*",
"*Args:",
"*assert ('fo',) == ('',)",
"*At index 0 diff: 'fo' != ''*",
"*Use -v to get the full diff*",
"*Kwargs:*",
"*assert {} == {'bar': 4}*",
"*Right contains* more item*",
"*{'bar': 4}*",
"*Use -v to get the full diff*",
]
result.stdout.fnmatch_lines(expected_lines)


def test_missing_introspection(testdir):
testdir.makepyfile(
"""
Expand Down

0 comments on commit 449d3d0

Please sign in to comment.