Skip to content
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

Show detailed py.test assert introspect for call arguments #36

Merged
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
10 changes: 10 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ your ``pytest.ini`` file:
[pytest]
mock_traceback_monkeypatch = false

The plugin also adds introspection information on differing call arguments when
calling the helper methods. This features catches `AssertionError` raised in
the method, and uses py.test's own `advanced assertions`_ to return a better
diff.

This is useful when asserting mock calls with many/nested arguments and trying
to quickly see the difference.

.. _advanced assertions: https://pytest.org/latest/assert.html


Requirements
============
Expand Down
8 changes: 7 additions & 1 deletion pytest_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ def assert_wrapper(__wrapped_mock_method__, *args, **kwargs):
try:
__wrapped_mock_method__(*args, **kwargs)
except AssertionError as e:
__mock_self = args[0]
if __mock_self.call_args is not None:
actual_args, actual_kwargs = __mock_self.call_args
assert actual_args == args[1:]
assert actual_kwargs == kwargs
raise AssertionError(*e.args)


Expand Down Expand Up @@ -189,7 +194,8 @@ def wrap_assert_any_call(*args, **kwargs):

def wrap_assert_methods(config):
"""
Wrap assert methods of mock module so we can hide their traceback
Wrap assert methods of mock module so we can hide their traceback and
add introspection information to specified argument asserts.
"""
# Make sure we only do this once
if _mock_module_originals:
Expand Down
49 changes: 49 additions & 0 deletions test_pytest_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,25 @@ def assert_traceback():
raise AssertionError("DID NOT RAISE")


@contextmanager
def assert_argument_introspection(left, right):
"""
Assert detailed argument introspection is used
"""
try:
yield
except AssertionError as e:
# this may be a bit too assuming, but seems nicer then hard-coding
import _pytest.assertion.util as util
# NOTE: we assert with either verbose or not, depending on how our own
# test was run by examining sys.argv
verbose = any(a.startswith('-v') for a in sys.argv)
expected = '\n '.join(util._compare_eq_iterable(left, right, verbose))
assert expected in e.msg
else:
raise AssertionError("DID NOT RAISE")


@pytest.mark.skipif(sys.version_info[0] == 3 and sys.version_info[1] in (3, 4),
reason="assert_not_called not available in python 3.3 and 3.4")
def test_assert_not_called_wrapper(mocker):
Expand Down Expand Up @@ -357,6 +376,36 @@ def test_assert_called_once_with_wrapper(mocker):
stub.assert_called_once_with("foo")


def test_assert_called_args_with_introspection(mocker):
stub = mocker.stub()

complex_args = ('a', 1, set(['test']))
wrong_args = ('b', 2, set(['jest']))

stub(*complex_args)
stub.assert_called_with(*complex_args)
stub.assert_called_once_with(*complex_args)

with assert_argument_introspection(complex_args, wrong_args):
stub.assert_called_with(*wrong_args)
stub.assert_called_once_with(*wrong_args)


def test_assert_called_kwargs_with_introspection(mocker):
stub = mocker.stub()

complex_kwargs = dict(foo={'bar': 1, 'baz': 'spam'})
wrong_kwargs = dict(foo={'goo': 1, 'baz': 'bran'})

stub(**complex_kwargs)
stub.assert_called_with(**complex_kwargs)
stub.assert_called_once_with(**complex_kwargs)

with assert_argument_introspection(complex_kwargs, wrong_kwargs):
stub.assert_called_with(**wrong_kwargs)
stub.assert_called_once_with(**wrong_kwargs)


def test_assert_any_call_wrapper(mocker):
stub = mocker.stub()
stub("foo")
Expand Down