View on GitHub

Ann Molly Paul

learn -- code -- inspire

Unit testing in Django to mock timestamps

January 16, 2015

Unit testing is very important for confidence in your implementation and early detection of flaws. In case where you want to set some state to unit tests in django where your implementation is dependant on it, the mock library comes in handy.

This becomes tricky when you try to mock python's in built libraries, like for instance datetime. If you try to use a decorator a class or method, you'll run into a TypeError: can't set attributes of built-in/extension type datetime.datetime. To get around this, I used a with block.

with patch('app_name.datetime') as mock_date:
        mock_date.utcnow.return_value = UTC_NOW

But the drawback, that block has to be repeated in eery test.

The only way to truly make this more generic and DRY is to sublcass the built-in package you want to mock and sub-class you Test cases from that class.

from datetime import datetime
from mock import patch

from django.test import TestCase


class MockedDatetimeTestCase(TestCase):
    """
    Helper testcase to freeze datetime 
    """
    mocked_utcnow = datetime(2014, 12, 8, 3, 0)

    class MockedDatetime(datetime):
        """A python builtin cannot be easily mocked,
        so we're subclassing datetime and patching that instead.
        """
        @classmethod
        def utcnow(cls):
            return MockedDatetimeTestCase.mocked_utcnow

    def setUp(self):
        patcher = patch('app_name.datetime', self.MockedDatetime)
        self.addCleanup(patcher.stop)
        patcher.start()

You may have noticed that the patcher.stop is called in the setUp() class instead of the tearDown(). This is because, in Django, the tearDown is not guaranteed to be called.