覆盖unittest的auto_now

时间:2010-02-16 14:14:32

标签: python django unit-testing

我已经为数据库中的事件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非常明确地说明了。

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

  • 也许在Model类之外以不同的方式生成数据库数据。在哪里以及如何?
  • 以某种方式定义不同的类或更改类以在测试期间表现不同,例如

_

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

或许有更简单的方法可以做到这一点......任何想法?

3 个答案:

答案 0 :(得分:2)

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

我创建了一个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']

答案 1 :(得分:2)

对我来说灯具的问题是,我需要测试一些超过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

答案 2 :(得分:1)

另一种处理方法是在创建实例后使用QuerySet update,根据您的使用情况,这可能更有用。

在SQL级别执行update调用时,它将跳过验证,信号和自定义保存功能。它将需要一个可能影响性能的二级数据库调用,因此应该考虑使用它。

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)