Fel*_*arz 20 python testing time datetime unit-testing
当我使用业务逻辑编写时,我的代码通常取决于当前时间.例如,查看每个未完成订单并检查是否应发送发票的算法(这取决于作业结束后的天数).在这些情况下,创建发票不是由显式用户操作触发,而是由后台作业触发.
现在,在测试方面,这给我带来了一个问题:
到目前为止,我找到了两个解
毕竟,第二种方法对我来说更成功.因此,我正在寻找一种方法来设置Python的datetime + time模块返回的时间.设置日期通常就足够了,我不需要设置当前小时或秒(即使这样会很好).
有没有这样的实用工具?是否有可以使用的(内部)Python API?
time.time
实际上,Monkey-patching 可能就足够了,因为它为Python中几乎所有其他基于时间的例程提供了基础.这似乎可以很好地处理你的用例,而不需要采用更复杂的技巧,并且当你这样做时并不重要(除了像Queue.py和threading.py这样的少数stdlib包之外from time import time
你必须修补在他们进口之前):
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2010, 4, 17, 14, 5, 35, 642000)
>>> import time
>>> def mytime(): return 120000000.0
...
>>> time.time = mytime
>>> datetime.datetime.now()
datetime.datetime(1973, 10, 20, 17, 20)
Run Code Online (Sandbox Code Playgroud)
也就是说,在各种类型的自动化测试的模拟对象中,我很少需要这种方法,因为大多数时候它是我自己的应用程序代码需要模拟,而不是stdlib例程.毕竟,你知道他们已经工作了.如果您遇到自己的代码必须处理库例程返回的值的情况,您可能希望自己模拟库例程,至少在检查您自己的应用程序如何处理时间戳时.
到目前为止,最好的方法是构建您自己的日期/时间服务例程,您可以在应用程序代码中专门使用这些例程,并构建测试根据需要提供虚假结果的能力.例如,我有时会做一个更复杂的等价物:
# in file apptime.py (for example)
import time as _time
class MyTimeService(object):
def __init__(self, get_time=None):
self.get_time = get_time or _time.time
def __call__(self):
return self.get_time()
time = MyTimeService()
Run Code Online (Sandbox Code Playgroud)
现在在我的应用程序代码中我只是import apptime as time; time.time()
为了获取当前时间值,而在测试代码中我可以先apptime.time = MyTimeService(mock_time_func)
在我的setUp()
代码中提供假时间结果.
更新:多年后有一个替代方案,如Dave Forgac的答案所述.
该freezegun包是专为此目的作出.它允许您更改测试代码的日期.它可以直接使用,也可以通过装饰器或上下文管理器使用.一个例子:
from freezegun import freeze_time
import datetime
@freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
Run Code Online (Sandbox Code Playgroud)
有关更多示例,请参阅该项目:https://github.com/spulec/freezegun