如何覆盖当前时间?

5

我正在编写一款应用程序,它利用当前时间(通过 datetime.datetime.now()

为了调试目的,是否有一种方法可以覆盖此调用,以返回特定的时间戳?

作为备选方案,我可以编写一个函数来代替datetime.datetime.now(),并返回所需的任何内容(在生产环境中实际的当前时间和在调试时所需的测试时间),但可能有更具Python风格的方法来执行这些操作?


你可以使用 datetime.datetime(year, month, day, hour, minute, second) 来创建自己的时间戳,这是你需要的吗? - Burhan Khalid
@BurhanKhalid:不行。我在问题中提到,我可以编写一个函数来替换datetime.datetime.now()并返回所需的任何内容。但是我想在代码中保留datetime.datetime.now()并在代码的其他位置覆盖它。 - WoJ
@WoJ 或者,你可以改变你的设计,不要在你的函数/方法中调用 now(),让调用者负责传递时间。这本质上使用了函数式编程的核心思想 - 甚至有一篇关于函数式编程的文章 在 Python 网站上。这主要是因为:“函数不依赖于需要在运行测试之前复制的系统状态;相反,您只需要合成正确的输入,然后检查输出是否符合预期。” - metatoaster
2个回答

7

总的来说,您有以下几种选择:

  • 使用unittest.mock库,它可以在运行时用一个总是返回相同结果的虚拟函数替换原函数(或使用另一个能够实现相同功能的模拟库)。这意味着您无需修改原函数,但是对于调试而言,人们普遍认为使用模拟的方法进行猴子补丁并不是一种好的做法。我认为这是Python中最常用的解决此问题的方法。
  • 根据环境条件(系统实际的环境变量、全局状态或其他)修改您的函数以执行不同的操作。 这是最简单的方法,但也是最粗糙和最脆弱的方法,所以在调试完成后,您必须确保将其改回。
  • 修改您的函数,使其接受一个函数作为参数,并在正常操作中传递datetime.datetime.now作为该函数,但在测试中传递不同的东西(例如stub)。

我选择了第三个选项的一个版本(传递值datetime.datetime.now()而不是函数本身),并遇到了这种行为:https://dev59.com/Sa7la4cB1Zd3GeqPg6rv 那里的答案很好,只是想在这里发布以防其他人尝试同样的事情。 - victorlin

1
您可以使用 mock 库来模拟 datetime.datetime.now() 的使用:
import mock

def my_test():
    my_mock = mock.Mock(return_value=your_desired_timestamp)

    with mock.patch('mymodule.datetime.datetime.now', my_mock):
        # Here, all calls to `datetime.datetime.now` referenced by `datetime.datetime`
        # defined in `my_module` will be mocked to return `your_desired_timestamp`.

你无法模拟日期时间(以及日期/时间)方法,如此处所述:https://dev59.com/wm855IYBdhLWcg3wMRRV#4482067 - Balthazar Rouberol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接