From 8441253c7a2d80a5de3bf377bb0618c6a140e887 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Tue, 8 Mar 2016 16:16:28 +0100 Subject: [PATCH] Show detailed py.test assert introspect for call arguments --- pytest_mock.py | 8 +++++++- test_pytest_mock.py | 47 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/pytest_mock.py b/pytest_mock.py index 63e2a82..8217ef5 100644 --- a/pytest_mock.py +++ b/pytest_mock.py @@ -150,6 +150,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) @@ -185,7 +190,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: diff --git a/test_pytest_mock.py b/test_pytest_mock.py index 703d165..cdd6d6d 100644 --- a/test_pytest_mock.py +++ b/test_pytest_mock.py @@ -273,6 +273,23 @@ 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 can assert verbose explanation but we'd have to update tox.ini + expected = '\n '.join(util._compare_eq_iterable(left, right, False)) + assert expected in e.msg + else: + raise AssertionError("DID NOT RAISE") + + @pytest.mark.skipif(sys.version_info[:2] == (3, 4), reason="assert_not_called not available in python 3.4") def test_assert_not_called_wrapper(mocker): @@ -300,6 +317,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")