1

Similar to a setUp() method, is there a way to define in one place how a certain exception is handled for all the tests in a given TestCase test class?

My use-case: the stack trace of mock/patch's assert_any_call only gives the expected call it could not find, but I want to add the actual calls against the mock. Each unit test can add this info to the stack trace in an except clause, but I want it defined in one place to avoid bloated code.

dongle man
  • 133
  • 1
  • 7

1 Answers1

0

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)
dongle man
  • 133
  • 1
  • 7