热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

嘲笑默认=时区。对于单元测试-Mockingdefault=timezone.nowforunittests

Imtryingtowriteunittestsforadjangoappthatdoesalotofdatetimeoperations.Ihaveinsta

I'm trying to write unit tests for a django app that does a lot of datetime operations. I have installed mock to monkey patch django's timezone.now for my tests.

我正在为django应用程序编写单元测试,该应用程序执行大量的datetime操作。我为monkey patch django的时区安装了mock。现在对我的测试。

While I am able to successfully mock timezone.now when it is called normally (actually calling timezone.now() in my code, I am not able to mock it for models that are created with a DateTimeField with default=timezone.now.

当我能够成功模拟时区时。现在,在我的代码中,当它被正常调用时(实际上是调用timezone.now()时,我无法对使用默认=timezone.now的DateTimeField创建的模型进行模拟。


I have a User model that contains the following:

我的用户模型包含以下内容:

from django.utils import timezone
...
timestamp = models.DateTimeField(default=timezone.now)
modified = models.DateTimeField(default=timezone.now)
...
def save(self, *args, **kwargs):
    if kwargs.pop('modified', True):
        self.modified = timezone.now()
    super(User, self).save(*args, **kwargs)

My unit test looks like this:

我的单元测试是这样的:

from django.utils import timezone

def test_created(self):
    dt = datetime(2010, 1, 1, tzinfo=timezone.utc)
    with patch.object(timezone, 'now', return_value=dt):
        user = User.objects.create(username='test')
        self.assertEquals(user.modified, dt)
        self.assertEquals(user.timestamp, dt)

assertEquals(user.modified, dt) passes, but assertEquals(user.timestamp, dt) does not.

assertequal(用户。修改,dt)通过,但是assertEquals(用户)。时间戳,dt)没有。

How can I mock timezone.now so that even default=timezone.now in my models will create the mock time?

我怎么能模拟时区呢?现在,即使是default=timezone。在我的模型中会创建模拟时间吗?


Edit

编辑

I know that I could just change my unit test to pass a timestamp of my choice (probably generated by the mocked timezone.now)... Curious if there is a way that avoids that though.

我知道我可以更改我的单元测试来通过我所选择的时间戳(可能是由模拟的timezone生成的)……我很好奇是否有什么方法可以避免这种情况。

4 个解决方案

#1


11  

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.

我自己也遇到了这个问题。问题是模型是在mock修补了时区模块之前加载的,所以在表达式default=timezone时。现在进行评估,它将默认的kwarg设置为真正的时区。现在的功能。

The solution is the following:

解决办法如下:

class MyModel(models.Model):
    timestamp = models.DateTimeField(default=lambda: timezone.now())

#2


6  

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.

类似地,您可以编写助手上下文管理器来一次修补多个字段。

#3


0  

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.

假设您的用户模型生活在myapp\模型中。py需要在该文件中测试save()。问题是当你来自django的时候。在顶部的utils导入时区,它从django.utils导入。在您的测试中,您正在本地修补时区,它对您的测试没有影响,因为模块myapp\models。py已经提到了实际时区,看起来我们的补丁没有效果。

Try patching timezone from myapp\models.py, something like:

尝试从myapp\模型中修补时区。py,类似:

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)

#4


0  

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.

这是模拟时间的最好方法。


推荐阅读
author-avatar
大市低开_127
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有