模拟单元测试中的时间流逝

oiv*_*vio 19 python testing integration-testing mocking celery

我为客户建立了一个付费的CMS +发票系统,我需要对我的测试更加严格.

我将所有数据保存在Django ORM中,并且有一堆Celery任务以不同的时间间隔运行,以确保在用户不支付发票时发送新发票和发票提醒并减少访问权限.

例如,我希望能够运行以下测试:

  1. 创建新用户并为X天访问该站点生成发票

  2. 模拟X + 1天的传递,并运行我在Celery中设置的所有任务.

  3. 检查是否已向用户发出其他X天的新发票.

到目前为止我提出的KISS方法是在一台单独的机器上进行所有测试,并实际操作操作系统级别的日期/时间.所以测试脚本会:

  1. 将系统日期设置为第1天

  2. 创建新用户并为X天访问生成第一张发票

  3. 提前系统日期1天.运行我所有的芹菜任务.重复直到X + 1天"通过"

  4. 检查是否已签发新发票

它有点笨重,但我认为它可能会奏效.关于如何完成它的任何其他想法?

mad*_*jar 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))
Run Code Online (Sandbox Code Playgroud)

因为我们不能直接替换datetime.datetime.now,所以我们创建了一个伪日期时间类,它以相同的方式执行所有操作,除非在调用now时返回常量值.