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.