我为客户建立了一个付费的CMS +发票系统,我的测试需要更加严格。
我将所有数据保存在Django ORM中,并且有一堆Celery任务以不同的时间间隔运行,以确保在用户不支付发票时发送新发票和发票提醒并减少访问权限。
例如,我希望能够运行以下测试:
创建新用户并为X天访问网站生成发票
模拟X + 1天的传递,并运行我在Celery中设置的所有任务。
检查是否已向用户发出了其他X天的新发票。
到目前为止,我提出的KISS方法是在一台单独的机器上进行所有测试,并实际操作操作系统级别的日期/时间。所以测试脚本会:
将系统日期设置为第1天
创建新用户并为X天访问生成第一张发票
提前1天系统日期。运行我所有的芹菜任务。重复直到X + 1天“通过”
检查是否已签发新发票
它有点笨重,但我认为它可能会奏效。关于如何完成它的任何其他想法?
答案 0 :(得分:18)
您可以使用mock更改用于获取时间的函数的返回值(例如datetime.datetime.now
)。
有多种方法可以这样做(参见模拟文档),但这里有一个:
import unittest
import datetime
from mock import patch
class SomeTestCase(unittest.TestCase):
def setUp(self):
self.time = datetime.datetime(2012, 5, 18)
class fakedatetime(datetime.datetime):
@classmethod
def now(cls):
return self.time
patcher = patch('datetime.datetime', fakedatetime)
self.addCleanup(patcher.stop)
patcher.start()
def test_something(self):
self.assertEqual(datetime.datetime.now(), datetime.datetime(2012, 5, 18))
self.time = datetime.datetime(2012, 5, 20)
self.assertEqual(datetime.datetime.now(), datetime.datetime(2012, 5, 20))
因为我们无法直接替换datetime.datetime.now
,所以我们创建了一个假日期时间类,它以相同的方式执行所有操作,除非在调用now时返回常量值。
答案 1 :(得分:4)
如果不使用特殊的模拟库,我建议准备处于模拟模式的代码(可能是通过全局变量)。在模拟模式中,而不是调用正常的时间函数(如time.time()或其他),你可以调用一个模拟时间函数,它返回你特殊情况下你需要的任何东西。
我会投票决定更改系统时间。这似乎不是一个单元测试,而是一个功能测试,因为它无法与该机器上的任何其他内容并行完成。
答案 2 :(得分:1)
您还可以查看freezegun
模块。 Github-https://github.com/spulec/freezegun
从他们的文档中
from freezegun import freeze_time
import datetime
@freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)