Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

factoryboy not working with freezegun

simple model(models.py):

from django.db import models

class MyModel(models.Model):
    start_date = models.DateField()

simple factory(test_factories.py):

from datetime import date
import factory
from .models import MyModel

class MyModelFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = MyModel

    start_date = date.today()

In manage.py shell:

In [1]: from datetime import date

In [2]: from freezegun import freeze_time

In [3]: from polls.test_factories import MyModelFactory

In [4]: date.today()
Out[4]: datetime.date(2017, 8, 16)

In [5]: with freeze_time(date(1999,9,9)):
   ...:     print(date.today())
   ...:     m = MyModelFactory()
   ...:     print(m.start_date)
   ...: 
1999-09-09
2017-08-16

current date is 2017-08-16 and fake date is 1999-09-09. Inside freeze_time, date.today() give fake date but factoryboy is not affected by freezegun. It still give real current date.

  • Is this bug? If yes, bug with factoryboy or freezegun?

  • How to solve this? In other words, How to make factoryboy give fake date? (For now, I use MyModelFactory(start_date=date.today()) to create model with fake date.)

freezegun version: 0.3.9

factoryboy version: 2.8.1

like image 346
Pyae Avatar asked Aug 16 '17 16:08

Pyae


2 Answers

The issue is that date.today() is evaluated when python parses the factory declaration; and factory_boy only receives the resulting date instance.

This is part of the core Python behavior — and can't be overridden by factory_boy.

The proper solution for this problem would be to use a factory.LazyFunction declaration:

class MyModelFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = MyModel

    # Note that we simply pass a callable.
    start_date = factory.LazyFunction(date.today)

You might also want to take a look at factory.fuzzy.FuzzyDate which would generate random dates in a given timespan.

like image 60
Xelnor Avatar answered Oct 31 '22 02:10

Xelnor


LazyFunction(date.today) doesn't solve the problem because date.today is bound before the time is frozen (datetime.date gets overridden with FakeDate).

LazyFunction(lambda: date.today()) does solve the problem because it's evaluated after freezing time.

like image 25
tkacperek Avatar answered Oct 31 '22 00:10

tkacperek