Avoid Redundant @patch When Mocking with Python

Viewed 3272

Coming from a static programming language background, I am wondering how to best do mocking in Python. I am accustomed to dependency injection. Within tests, mocks are created and passed to the System Under Test (SUT). However, looking at Mock and other mock frameworks for Python, it appears that the types/functions/etc. in the module are replaced on a test-by-test basis.

Particularly, with Mock, atop each unit test you say @patch('some.type.in.the.module.under.test') for each type/function/etc. you want to mock. For the lifetime of the test those things are mocked, then they are reverted. Unfortunately, across tests, the fixture is pretty close to the same and you end up repeating your @patches over and over again.

I want a way to share a collection of patches across unit tests. I also want carry through tweaks to the fixture in a composable way. I am okay using a context manager instead of a decorator.

4 Answers

I would also recommend decorators, as you can avoid redundant patch. And not just that, using parameterized decorators, you can control custom fixtures for each decorator. Example:

def patch_example(custom_value=None):
    def _patch(test_func):
        @mock.patch('some.type.in.the.module.under.test')
        def _patch_it(mocked_function):
            mocked_function = custom_value
            return test_func(self)
        return wraps(test_func)(_patch_it)
    return _patch

class ExampleTestCase(object):

    @patch_example(custom_value='new_value')
    def test_method_1(self):
        # your test logic here, with mocked values already defined in decorator

    @patch_example(custom_value='new_value_2')
    def test_method_2(self):
        # your test logic here, with mocked values already defined in decorator
Related