如何在pytest中模拟/设置系统日期?

ada*_*rsh 8 python pytest

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

sas*_*shk 11

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

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

    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()
    
    Run Code Online (Sandbox Code Playgroud)

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

    import datetime
    
    def test_patched_date(monkeypatch):
        monkeytest.setenv('MYDATE', '05-31-2014')
        assert datetime.date.today() == datetime.date(2014, 5, 31)
    
    Run Code Online (Sandbox Code Playgroud)
  2. Monkeypatch datetime功能:

    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
    
    Run Code Online (Sandbox Code Playgroud)

  • 我现在意识到我指的是修补的 [这个问题](http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch)。因此,如果被测模块 (mut.py) 在您修补 `datetime.datetime` 之前导入了 datetime,请改为修补 `mut.datetime`。 (2认同)

Bru*_*ira 10

AFAIK,你无法模拟内置方法.

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

# mymodule.py

def get_today():
   return datetime.date.today()
Run Code Online (Sandbox Code Playgroud)

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

def test_something():
    with mock.patch('mymodule.get_today', return_value=datetime.date(2014, 6, 2)):
        ...
Run Code Online (Sandbox Code Playgroud)

您也可以使用freezegun模块.


Jas*_*mbs 6

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

使用freezegunrepo)。

从自述文件:

from freezegun import freeze_time

@freeze_time("2012-01-14")
def test():
    assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
Run Code Online (Sandbox Code Playgroud)