关于python:如何在pytest中模拟/设置系统日期?

How to mock/set system date in pytest?

在我的一些测试中,由于时间和时区问题,我遇到了Travis失败的问题,所以我想模拟系统时间进行测试。 我怎样才能做到这一点?


有两种方法可以实现这一目标:

  • 根据Bruno的建议创建您将调用的函数而不是datetime.datetime.now(),但这里有不同的实现:

    1
    2
    3
    4
    5
    6
    7
    8
    import os
    import datetime

    def mytoday():
     if 'MYDATE' in os.environ:
         return datetime.datetime.strptime(os.getenv('MYDATE'), '%m-%d-%Y').date()
     else:
         return datetime.date.today()

    然后,在您的测试中,您只需monkeypatch环境变量:

    1
    2
    3
    4
    5
    import datetime

    def test_patched_date(monkeypatch):
        monkeytest.setenv('MYDATE', '05-31-2014')
        assert datetime.date.today() == datetime.date(2014, 5, 31)
  • Monkeypatch datetime功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import datetime
    import pytest

    FAKE_TIME = datetime.datetime(2020, 12, 25, 17, 05, 55)

    @pytest.fixture
    def patch_datetime_now(monkeypatch):

        class mydatetime:
            @classmethod
            def now(cls):
                return FAKE_TIME

        monkeypatch.setattr(datetime, 'datetime', mydatetime)


    def test_patch_datetime(patch_datetime_now):
        assert datetime.datetime.now() == FAKE_TIME

  • AFAIK,你无法模拟内置方法。

    我经常做的一种方法是将代码更改为不直接使用datetime来获取日期,而是在某处使用包装函数:

    1
    2
    3
    4
    # mymodule.py

    def get_today():
       return datetime.date.today()

    这使得在测试中只需mock就可以了:

    1
    2
    3
    def test_something():
        with mock.patch('mymodule.get_today', return_value=datetime.date(2014, 6, 2)):
            ...

    您也可以使用freezegun模块。


    @ Brian-Kruger的答案是最好的答案。 我已投票取消删除它。 同时...

    使用freezegun(repo)。

    来自README:

    1
    2
    3
    4
    5
    from freezegun import freeze_time

    @freeze_time("2012-01-14")
    def test():
        assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)