我在Django写了一个拍卖系统。我想编写单元测试,但应用程序是时间敏感的(例如,广告客户的收费金额取决于他们的广告在网站上的活动时长)。测试此类应用程序的好方法是什么?
这是一个可能的解决方案:一个DateFactory class,它提供了一些方法来生成测试中的可预测日期和生产中的实时值。你对这种方法有什么想法,或者你在实践中尝试过其他的东西吗?
答案 0 :(得分:3)
在您提供的链接中,作者有点拒绝为单元测试添加额外参数到您的方法的想法,但在某些情况下,我认为您可以证明这只是业务逻辑的扩展。在我看来,它是一种控制反转的形式,可以使你的模型更灵活,甚至可能更具表现力。例如:
def is_expired(self, check_date=None):
_check_date = check_date or datetime.utcnow()
return self.create_date + timedelta(days=15) < _check_date
基本上,这允许我的单元测试提供自己的日期/时间,以验证我的逻辑。
引用博客中的论点似乎是这会破坏API。但是,我遇到了一些情况,其中生产用例要求用替代值取代当前日期/时间。换句话说,控制方法的反转最终成为我应用程序的必要部分。
答案 1 :(得分:1)
一般情况下,我尝试使生产代码将日期对象作为输入(语义允许的地方)。在许多测试情况下,您描述的DateFactory就是人们所做的事情。
在Python中,您还可以直接更改静态模块方法Datetime.now或Time.now。你需要小心,在测试的拆解部分更换它们。当您无法(或者很难)改变您正在测试的课程时,这尤其有用。
要做到这一点,你有
def setUp(self)
self.oldNow = Datetime.now
Datetime.now = self._fakenow
...
def tearDown(self)
Datetime.now = self.oldNow
如果设置方法失败的话,我会做最后的替换。
对于许多情况,自定义DateFactory使用起来更安全,特别是如果您不得不担心人们忘记了tearDown部分。