How to mock django timezone.now in a abstract model
I'm unable to mock timezone.now in the model's created field. The test fails due unmocked/current datetime.
I tried patch('django.utils.timezone.now') to no avail.
# app/models.py
from django.utils import timezone
class BaseModel(models.Model):
created = models.DateTimeField(default=timezone.now, editable=False)
class Meta:
abstract = True
class MyModel(BaseModel):
...
# app/tests/test.py
from app.models import MyModel
from datetime import dateHow to mock django timezone.now in a abstract modeltime
from django.utils import timezone
def test_(self):
dt=datetime(2018, 1, 24, tzinfo=timezone.utc)
with patch('app.models.timezone.now', return_value=dt):
instance = MyModel.objects.create()
assert instance.created == dt
You either need to patch the default of the model or patch the 'django.utils.timezone.now' before you import the model you are testing:
from unittest.mock import patch
from datetime import datetime
from django.utils import timezone
def test_created_field_patch_before_import(monkeypatch):
dt = datetime(2018, 1, 24, tzinfo=timezone.utc)
with patch("django.utils.timezone.now", return_value=dt):
# Import AFTER patch so that default=timezone.now captures the mocked function
from app.models import MyModel
instance = MyModel.objects.create()
assert instance.created == dt
This might not work for other models/tests if you are testing more than one model. A better way (IMHO) is to patch the default of the model:
from datetime import datetime
from django.utils import timezone
from app.models import MyModel
def test_created_default_patching(db):
dt = datetime(2018, 1, 24, tzinfo=timezone.utc)
field = MyModel._meta.get_field("created")
# store original default so we can restore it
original_default = field.default
# patch
field.default = lambda: dt
try:
instance = MyModel.objects.create()
assert instance.created == dt
finally:
# restore after the test so other tests do NOT break
field.default = original_default
This test is isolated and dont mess with other tests that come after.