当我使用业务逻辑编写代码时,我的代码通常依赖于当前时间。例如,算法查看每个未完成的订单,并检查是否应该发送发票(这取决于作业结束后的天数)。在这些情况下,创建发票不是由显式用户操作触发的,而是由后台作业触发的。
现在,当涉及到测试时,这给我带来了一个问题:
到目前为止,我找到了两个解决方案:
毕竟,第二种方法对我来说要成功得多。因此,我正在寻找一种方法来设置Python的datetime+time模块返回的时间。设置日期通常就足够了,我不需要设置当前的小时或秒(尽管这样会很好)。
有这样的实用工具吗?有没有可以使用的(内部) Python API?
发布于 2017-07-13 04:04:25
freezegun包就是专门为此目的而开发的。它允许您更改测试代码的日期。它可以直接使用,也可以通过装饰器或上下文管理器使用。举个例子:
from freezegun import freeze_time
import datetime
@freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
有关更多示例,请参阅项目:https://github.com/spulec/freezegun
发布于 2010-04-18 02:19:49
实际上,为time.time
打补丁可能就足够了,因为它为Python中几乎所有其他基于时间的例程提供了基础。这似乎很好地处理了您的用例,而不需要求助于更复杂的技巧,而且当您这样做时也无关紧要(除了像Queue.py和threading.py这样的少数执行from time import time
的stdlib包,在这种情况下,您必须在导入它们之前打补丁):
>>> 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)
也就是说,在为各种类型的自动化测试模拟对象的多年中,我很少需要这种方法,因为大多数情况下,需要模拟的是我自己的应用程序代码,而不是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()
现在在我的应用程序代码中,我只是执行import apptime as time; time.time()
来获取当前时间值,而在测试代码中,我可以首先在我的setUp()
代码中执行apptime.time = MyTimeService(mock_time_func)
,以提供假的时间结果。
更新:几年后,正如Dave Forgac's answer中指出的那样,有了另一种选择。
发布于 2010-04-17 20:36:15
您可以通过创建一个自定义的datetime模块(甚至是一个假的-请参见下面的示例)作为代理来修补系统,然后将其插入到sys.modules字典中。从那时起,每次导入到datetime模块都将返回您的代理。
datetime类仍然需要注意,特别是当有人执行from datetime import datetime
时;为此,您只需为该类添加另一个代理即可。
这是我所说的一个例子--当然,这只是我在5分钟内抛出的东西,可能有几个问题(例如,datetime类的类型不正确);但希望它已经有用了。
import sys
import datetime as datetime_orig
class DummyDateTimeModule(sys.__class__):
""" Dummy class, for faking datetime module """
def __init__(self):
sys.modules["datetime"] = self
def __getattr__(self, attr):
if attr=="datetime":
return DummyDateTimeClass()
else:
return getattr(datetime_orig, attr)
class DummyDateTimeClass(object):
def __getattr__(self, attr):
return getattr(datetime_orig.datetime, attr)
dt_fake = DummyDateTimeModule()
最后--它值得吗?
坦率地说,我更喜欢我们的第二个解决方案,而不是这个:-)。
是的,python是一种非常动态的语言,你可以做很多有趣的事情,但是以这种方式修补代码总是有一定程度的风险,即使我们在这里谈论的是测试代码。
但最重要的是,我认为附件函数将使测试补丁更加明确,而且您的代码将在将要测试的内容方面更加明确,从而提高可读性。
因此,如果更改不是太昂贵,我会采用您的第二种方法。
https://stackoverflow.com/questions/2658026
复制相似问题