Mocking Django Timezone

I use django.utils.timezone.now() in a lot of my code. It returns the datetime in the timezone specified in settings.py. One side effect of using this function is that during testing, you may want “now()” to be a fixed date time. No worries. Mock to the rescue. Here is the code:

import datetime

from django.test import TestCase
from django.utils import timezone

import mock

# Make now() a constant
NOW_FOR_TESTING = datetime.datetime(2015, 10, 10, 10)


# This is the function that replaces django.utils.timezone.now()
def mocked_now():
    return NOW_FOR_TESTING


# This function shows that the mocking is in effect even outside of the TestMyTest scope.
def a_func():
    return timezone.now()


@mock.patch('django.utils.timezone.now', side_effect=mocked_now)
class TestMyTest(TestCase):
    def test_time_zone(self, *args):
        # After patching, mock passes in some extra vars. Put *args to handle them.
        self.assertEqual(timezone.now(), NOW_FOR_TESTING)
        self.assertEqual(timezone.now().date(), NOW_FOR_TESTING.date())
        self.assertEqual(mocked_now(), NOW_FOR_TESTING)

 

Django Testing using Mock

Two important 3rd party testing tools for Django are Mock and Mommy. Both allow you to quickly create instances of Django models for testing. The advantage of Mock is it is fast because it does not require a test database to be setup. It is used primarily for unit testing.

Here is a skeleton of a mock test:

import unittest
import mock

from models import MyModel

class TestMyCode(unittest.TestCase):
    def test_1(self):
        instance = mock.Mock(spec=MyModel)
        # Do something with instance

Put this in your tests.py file for the app. Then run using:

python manage.py test my_app.TestMyCode