Skip to content Skip to sidebar Skip to footer

Making A Wrapper For `mock.patch`

Some customized patches from mock.patch I want to use over and over without littering my test code with copy-pastes of the patch setup. e.g. this very handy patch of datetime.date,

Solution 1:

Here's a resource manager class that will do that for you. Since you might want to put it in a separate file from your test classes, it uses inspect to look up the calling module, so that it can pass the correctly qualified target module name to mock.patch.

import datetime
import inspect
# import mock according to your python version

class mock_datetime(object):

    def __init__(self, target, new_utcnow):
        self.new_utcnow = new_utcnow
        self.target = target

    def __enter__(self):
        calling_module = inspect.getmodule(inspect.stack()[1][0])
        target_from_here = calling_module.__name__ + '.' + self.target
        self.patcher = mock.patch(target_from_here)
        mock_dt = self.patcher.start()
        mock_dt.datetime.utcnow.return_value = self.new_utcnow.replace(tzinfo=None)
        mock_dt.datetime.side_effect = lambda *args, **kw: datetime.datetime(*args, **kw)
        return mock_dt

    def __exit__(self, *args, **kwargs):
        self.patcher.stop()

You can then invoke it with

with mock_datetime('mymodule.datetime', datetime.datetime(2016, 3, 23)):
    assert mymodule.datetime.datetime.utcnow() == datetime.datetime(2016, 3, 23)

Solution 2:

The solution by @brandones is excellent! But I found it easier to use if you leave out the inspection, like this:

# testhelpers.py
import unittest.mock as mock
import datetime

class MockDatetime():
    def __init__(self, target, utcnow):
        self.utcnow = utcnow
        self.target = target

    def __enter__(self):
        self.patcher = mock.patch(self.target)
        mock_dt = self.patcher.start()
        mock_dt.datetime.utcnow.return_value = self.utcnow.replace(tzinfo=None)
        mock_dt.datetime.side_effect = lambda *args, **kw: datetime.datetime(*args, **kw)
        return mock_dt

    def __exit__(self, *args, **kwargs):
        self.patcher.stop()


# testhelpers_test.py
import datetime
from testhelpers import MockDatetime

def test__mock_datetime():
    with MockDatetime('testhelpers_test.datetime', datetime.datetime(2019, 4, 29, 9, 10, 23, 1234)):
        assert datetime.datetime.utcnow() == datetime.datetime(2019, 4, 29, 9, 10, 23, 1234)

Post a Comment for "Making A Wrapper For `mock.patch`"