【问题标题】:Overwrite auto_now for unittest为单元测试覆盖 auto_now
【发布时间】:2010-02-16 14:14:32
【问题描述】:

我已经为数据库中的事件定义了一些时间戳为auto_now_add,因为信息应该与存储事件的时间戳一起存储。

事件的描述类似于

class NewEvent(models.Model):
    '''
    Individual event
    '''
    name = models.CharField(max_length=100)
    quantity = models.FloatField(null=True)
    timestamp = models.DateTimeField(auto_now_add=True)

为了测试模块,我在test.py 文件中的数据库中生成一些信息,这样:

    for event in EVENT_TYPES:
        time = datetime.datetime.now() - datetime.timedelta(days=1)
        for i in range(48):
            time = time.replace(hour=i / 2)
            NewEvent(name=event,
                     timestamp=time,
                     quantity=i).save()

我必须生成带有昨天时间戳的事件(然后模块将汇总它们)。问题是您无法覆盖时间戳。时间戳是它产生事件的时间,documentation 非常清楚地说明了这一点。

那么,如何为测试生成具有适当时间戳的数据?我有几个想法:

  • 可能在模型类之外以不同的方式生成数据库数据。地点和方式?
  • 以某种方式定义不同的类或更改类以在测试期间表现不同,例如

_

 if testing:
     timestamp = models.DateTimeField(auto_now_add=True)
 else:
     timestamp = models.DateTimeField(auto_now_add=False)

或者也许有更简单的方法来做到这一点......有什么想法吗?

【问题讨论】:

  • timestamp = models.DateTimeField(auto_now_add=testing) 简化一下怎么样?
  • testing 变量在测试时是否为真?那会很棒,但在这种情况下,我认为应该是 auto_now_add=not testing 之类的......
  • 这是你的问题和你的榜样,请随时解决。
  • 对于动态选项,请参阅下面的答案。

标签: python django unit-testing


【解决方案1】:

另一种处理方法是在创建实例后使用QuerySet update,这可能更有用,具体取决于您的用例。

由于update 调用在 SQL 级别执行,它将跳过验证、信号和自定义保存功能。它需要一个辅助数据库调用,这可能会影响性能,因此应慎重使用。

for event in EVENT_TYPES:
    time = datetime.datetime.now() - datetime.timedelta(days=1)
    for i in range(48):
        time = time.replace(hour=i / 2)
        instance = NewEvent(name=event, quantity=i).save()
        NewEvent.objects.filter(pk=instance.pk).update(timestamp=time)

【讨论】:

    【解决方案2】:

    对我来说,fixture 的问题是我需要测试某些超过 30 天的记录不会被返回,而不是 30 天的记录会被返回......以一种懒惰的方式)。所以我选择做的是模拟 django 用来获取要使用的日期时间的 timezone.now 函数。

    from django.utils import timezone 
    
    class SomeTestCase(TestCase):
        def test_auto_add(self):
            now = timezone.now()
            now_31 = now - datetime.timedelta(days=31)
            self.mock('timezone.now', returns=now_31, tracker=None)
            SomeObject.objects.create() # has auto_now_add field ...   
    

    我使用minimocktest进行模拟

    【讨论】:

    【解决方案3】:

    我已经设法使用夹具创建了覆盖默认值的数据。

    我创建了一个test_data.json 文件,其中包含以下格式的数据:

    [
    {
        "model": "stats_agg.newevent",
        "pk": 1,
        "fields": {
            "name": "event1",
            "quantity":0.0,
            "timestamp": "2010-02-15 00:27:40"
         }
    },
    {
        "model": "stats_agg.newevent",
        "pk": 2,
        "fields": {
            "name": "event1",
            "quantity":1.0,
            "timestamp": "2010-02-15 00:27:40"
         }
    },
    ...
    

    然后添加到测试单元中

    class SimpleTest(TestCase):
       fixtures = ['test_data.json']
    

    【讨论】:

    • 夹具不规则,他们有严重的问题。使用Factories
    猜你喜欢
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    相关资源
    最近更新 更多