猿问

如何冻结 datetime.now 以进行单元测试

我有一个使用函数返回默认日期时间的模型:


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,但日期时间并未冻结,因为它在计算时仍使用今天的日期c1.q1_results_date。


我该如何纠正这个问题?


ITMISS
浏览 161回答 1
1回答

胡子哥哥

这不起作用的原因是因为您调用了该函数。因此,这意味着datetime在解释类时对 进行求值,所以这基本上是在您启动服务器时进行的。在那一刻,冷冻枪还没有激活。因此,这也意味着如果您稍后运行服务器一段时间,并且年份增加,它仍将使用旧值。您可以将可调用对象传递给默认值,从而使用辅助函数,例如:def quarter_results_date(month):    yr = datetime.datetime.now().year    __, dy = calendar.monthrange(yr, month)    return datetime.datetime(        yr,        month,        dy    )def quarter_results_date_first():    return quarter_results_date(1)class Company(models.Model):    q1_results_date = models.DateField(        verbose_name='Q1 financial results',        default=quarter_results_date_first,        blank=False,        null=False,    )请注意, 没有使用括号default=quarter_results_date_first,因此我们将引用传递给函数,而不是日期时间值。
随时随地看视频慕课网APP

相关分类

Python
我要回答