10👍
I just ran into this issue myself. The problem is that models are loaded before mock has patched the timezone module, so at the time the expression default=timezone.now
is evaluated, it sets the default
kwarg to the real timezone.now
function.
The solution is the following:
class MyModel(models.Model):
timestamp = models.DateTimeField(default=lambda: timezone.now())
17👍
Here’s a method you can use that doesn’t require altering your non-test code. Just patch the default
attributes of the fields you want to affect. For example–
field = User._meta.get_field('timestamp')
mock_now = lambda: datetime(2010, 1, 1)
with patch.object(field, 'default', new=mock_now):
# Your code here
You can write helper functions to make this less verbose. For example, the following code–
@contextmanager
def patch_field(cls, field_name, dt):
field = cls._meta.get_field(field_name)
mock_now = lambda: dt
with patch.object(field, 'default', new=mock_now):
yield
would let you write–
with patch_field(User, 'timestamp', dt):
# Your code here
Similarly, you can write helper context managers to patch multiple fields at once.
- [Django]-Pip install -r requirements.txt [Errno 2] No such file or directory: 'requirements.txt'
- [Django]-How to use subquery in django?
- [Django]-Django REST Framework (DRF): Set current user id as field value
6👍
There is another easy way to do the above thing.
import myapp.models.timezone
from unittest.mock import patch
@patch('django.utils.timezone.now')
def test_created(self, mock_timezone):
dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
mock_timezone.return_value = dt
user = User.objects.create(username='test')
self.assertEquals(user.modified, dt)
self.assertEquals(user.timestamp, dt)
This is the best way to mock timezone.now.
- [Django]-How django time zone works with model.field's auto_now_add
- [Django]-"Post Image data using POSTMAN"
- [Django]-How can I get tox and poetry to work together to support testing multiple versions of a Python dependency?
3👍
Looks like you are patching timezone in the wrong place.
Assuming your User
model lives in myapp\models.py
and you want to test save()
in that file. The problem is that when you from django.utils import timezone
at the top, it imports it from django.utils
. In your test you are patching timezone
locally, and it has no effect on your test, since module myapp\models.py
already has a reference to the real timezone
and it looks like our patching had no effect.
Try patching timezone
from myapp\models.py
, something like:
import myapp.models.timezone
def test_created(self):
with patch('myapp.models.timezone') as mock_timezone:
dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
mock_timezone.now.return_value = dt
assert myapp.models.timezone.now() == dt
user = User.objects.create(username='test')
self.assertEquals(user.modified, dt)
self.assertEquals(user.timestamp, dt)
- [Django]-Django {{ MEDIA_URL }} blank @DEPRECATED
- [Django]-Cannot import name patterns
- [Django]-Not able to create super user with Django manage.py