为单元测试覆盖auto_now
我在数据库里为一些事件定义了时间戳,使用的是 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()
我需要生成一些事件,时间戳是昨天的(这个模块会对这些事件进行汇总)。问题是,时间戳是不能被覆盖的。时间戳就是事件发生的时间,文档里说得很清楚。
那么,怎么才能生成带有合适时间戳的数据来进行测试呢?我有几个想法:
- 也许可以用不同的方式生成数据库数据,放在模型类之外。那应该在哪里做呢?
- 或者定义一个不同的类,或者在测试时让这个类表现得不一样,类似于:
_
if testing:
timestamp = models.DateTimeField(auto_now_add=True)
else:
timestamp = models.DateTimeField(auto_now_add=False)
或者说,也许还有更简单的方法来做到这一点……有什么想法吗?
3 个回答
3
对我来说,使用测试数据的一个问题是,我需要检查一些超过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这个工具。
7
处理这个问题的另一种方法是,在创建实例后使用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
我成功地用一个固定数据文件覆盖了默认值。
我创建了一个 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']