Skip to content
Merged
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
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Releases
========

UNRELEASED
----------

* `#641 <https://github.com/pytest-dev/pytest-mock/pull/641>`_: Failures of mock assertions such as ``assert_called_with`` are again reported only once, instead of two or three times with the original error from the ``mock`` module chained before them.

3.16.1
------

Expand Down
8 changes: 6 additions & 2 deletions src/pytest_mock/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,9 @@ def assert_wrapper(
msg += "\n\npytest introspection follows:\n" + introspection
e = AssertionError(msg)
e._mock_introspection_applied = True # type:ignore[attr-defined]
raise e # noqa:TRY201
# Suppress the context, otherwise pytest shows the original error
# (and the mock frames) chained before this one.
raise e from None


def _unpack_expected_call(expect_call: Any) -> tuple[Any, Any] | None:
Expand Down Expand Up @@ -651,7 +653,9 @@ def assert_has_calls_wrapper(
msg += "\n\npytest introspection follows:\n" + introspection
e = AssertionError(msg)
e._mock_introspection_applied = True # type:ignore[attr-defined]
raise e # noqa:TRY201
# Suppress the context, otherwise pytest shows the original error
# (and the mock frames) chained before this one.
raise e from None


def wrap_assert_not_called(*args: Any, **kwargs: Any) -> None:
Expand Down
29 changes: 29 additions & 0 deletions tests/test_pytest_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,35 @@ def test_foo(mocker):
result = testdir.runpytest()
assert "pytest introspection follows:" not in result.stdout.str()

@pytest.mark.parametrize(
"assertion",
[
"stub.assert_called_with(2)",
# assert_called_once_with calls assert_called_with internally,
# so both wrappers are involved.
"stub.assert_called_once_with(2)",
"stub.assert_not_called()",
"stub.assert_has_calls([mocker.call(2)])",
],
)
def test_no_chained_tracebacks(self, testdir: Any, assertion: str) -> None:
"""
The wrapped assertions report the failure only once, without the
original exception from the mock module chained to it.
"""
testdir.makepyfile(
f"""
def test_foo(mocker):
stub = mocker.stub()
stub(1)
{assertion}
"""
)
result = testdir.runpytest()
result.assert_outcomes(failed=1)
assert "During handling of the above exception" not in result.stdout.str()
assert "mock.py" not in result.stdout.str()


class TestAssertHasCalls:
"""``assert_has_calls``, including the shapes accepted as expected calls."""
Expand Down
Loading