繁体   English   中英

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

[英]How to freeze datetime.now for unit testing

我有一个 model 使用 function 返回默认日期时间:

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时仍使用今天的日期。

我该如何纠正?

这不起作用的原因是因为您调用了 function。 因此,这意味着在解释datetime时会评估日期时间,所以这基本上是在您启动服务器时。 在那一刻,冷冻枪尚未激活。

因此,这也意味着,如果您稍后运行服务器一段时间,并且年份增加,它仍将使用旧值。

您可以将可调用对象传递给默认值,从而使用帮助程序 function 例如:

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没有使用括号,因此我们传递了对 function 的引用,而不是日期时间值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM