Как заморозить datetime.now для модульного тестирования - PullRequest
2 голосов
/ 10 июля 2020

У меня есть модель, которая использует функцию для возврата даты и времени по умолчанию:

class Company(models.Model):
    q1_results_date = models.DateField(
        verbose_name='Q1 financial results',
        default=quarter_results_date(1),
        blank=False,
        null=False,
    )

def quarter_results_date(month):
    return datetime.datetime(
        datetime.datetime.now().year,
        month,
        calendar.monthrange(datetime.datetime.now().year, month)[1]
    )

Я хочу провести модульное тестирование, что требует от меня установки datetime.now () на известное значение. Для этого я использую freezegun.freeze_time:

def test_quarter_results_date(self):
    with freeze_time("2012-01-14"):
        print('check datetime.now()', datetime.now())
        c = Company.objects.create()
    ...

Однако, хотя оператор print показывает 2012-01-14, datetime не замораживается, поскольку он по-прежнему использует сегодняшнюю дату, когда оценка c1.q1_results_date.

Как я могу это исправить?

1 Ответ

2 голосов
/ 10 июля 2020

Причина, по которой это не сработает, состоит в том, что вы вызываете функцию. Таким образом, это означает, что datetime оценивается при интерпретации класса, так что в основном это происходит при запуске сервера. В этот момент freezegun еще не активен.

Таким образом, это также означает, что если вы позже запустите сервер в течение некоторого времени, и год будет увеличиваться, он все равно будет использовать старое значение.

Вы можете передать вызываемый объект в значение по умолчанию и, таким образом, использовать вспомогательную функцию, например:

def quarter_results_date(month):
    yr = datetime.datetime.now().year
    __, dy = calendar.monthrange(yr, month)
    return datetime.datetime(
        yr,
        month,
        dy
    )

def <b>quarter_results_date_first</b>():
    return quarter_results_date(1)

class Company(models.Model):
    q1_results_date = models.DateField(
        verbose_name='Q1 financial results',
        default=<b>quarter_results_date_first</b>,
        blank=False,
        null=False,
    )

Обратите внимание, что для default=quarter_results_date_first скобки не используются, поэтому мы передаем ссылку на функцию , а не значение даты и времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...