As @Jérôme pointed out, this can be achieved by creating a decorator to wrap your tests (e.g. https://stackoverflow.com/revisions/43938162/1)
Here is the code I ended up using:
import mock
from unittest import TestCase
from foo.bar import method_that_calls_my_class_method
def _add_mock_context(test_func):
"""This decorator is only meant for use in the MyClass class for help debugging test failures.
It adds to the stack trace the context of what actual calls were made against the method_mock,
without bloating the tests with boilerplate code."""
def test_wrapper(self, *args, **kwargs):
try:
test_func(self, *args, **kwargs)
except AssertionError as e:
# Append the actual calls (mock's exception only includes expected calls) for debugging
raise type(e)('{}\n\nActual calls to my_method mock were:\n{}'.format(e.message, self.method_mock.call_args_list))
return test_wrapper
class TestMyStuff(TestCase):
def setUp(self):
class_patch = mock.patch('mine.MyClass', autospec=True)
self.addCleanup(class_patch.stop)
class_mock = class_patch.start()
self.method_mock = class_mock.return_value.my_method
@_add_mock_context
def test_my_method(self):
method_that_calls_my_class_method()
self.method_mock.assert_any_call(arg1='a', arg2='b')
self.method_mock.assert_any_call(arg1='c', arg2='d')
self.method_mock.assert_any_call(arg1='e', arg2='f')
self.assertEqual(self.method_mock.call_count, 3)