当我使用业务逻辑编写时,我的代码通常取决于当前时间。例如,该算法查看每个未完成的订单并检查是否应发送发票(这取决于作业结束后的天数)。在这些情况下,创建发票不是由显式用户操作触发,而是由后台作业触发。
现在,当涉及到测试时,这给我带来了一个问题:
- 我可以轻松测试发票创建本身
- 但是,很难在测试中创建订单并检查后台作业是否在正确的时间识别正确的订单。
到目前为止,我找到了两个解决方案:
- 在测试设置中,计算相对于当前日期的工作日期。缺点:代码变得相当复杂,因为不再有明确的日期。有时,对于边缘情况,业务逻辑非常复杂,因此由于所有这些相对日期,调试变得困难。
- 我有自己的日期/时间访问器函数,我在整个代码中都使用这些函数。在测试中,我只是设置了一个当前日期,所有模块都得到这个日期。因此,我可以模拟 2 月份的订单创建,并轻松检查发票是否在 4 月份创建。缺点:第 3 方模块不使用这种机制,因此很难集成和测试这些。
毕竟,第二种方法对我来说更成功。因此,我正在寻找一种方法来设置 Python 的 datetime+time 模块返回的时间。设置日期通常就足够了,我不需要设置当前的小时或秒(即使这样会很好)。
有这样的实用程序吗?是否有我可以使用的(内部)Python API?
最佳答案
Monkey-patching time.time
实际上可能就足够了,因为它为 Python 中几乎所有其他基于时间的例程提供了基础。这似乎可以很好地处理您的用例,而无需诉诸更复杂的技巧,并且何时执行都没关系(除了少数 stdlib 包,例如 Queue.py 和 threading.py 执行 from time import时间
在这种情况下,您必须在它们被导入之前进行修补):
>>> 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 中所述.
关于python - 如何更改 Python 中所有模块的日期/时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2658026/