How to monkeypatch python's datetime.datetime.now with py.test?
我需要测试使用
你需要monkeypatch datetime.now函数。 在下面的例子中,我正在创建夹具,我可以在以后的其他测试中重复使用:
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, 5, 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 |
有
1 2 3 4 5 6 | from datetime import datetime from freezegun import freeze_time # $ pip install freezegun @freeze_time("Jan 14th, 2012") def test_nice_datetime(): assert datetime.now() == datetime(2012, 1, 14) |
这是我用来覆盖now()的工具,但保持datetime的其余部分工作(RE:satoru的问题)。
它没有经过广泛测试,但确实解决了在其他环境中使用datetime的问题。 对我来说,保持Django ORM使用这些日期时间值(特别是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | @pytest.fixture def freeze(monkeypatch): """ Now() manager patches datetime return a fixed, settable, value (freezes time) """ import datetime original = datetime.datetime class FreezeMeta(type): def __instancecheck__(self, instance): if type(instance) == original or type(instance) == Freeze: return True class Freeze(datetime.datetime): __metaclass__ = FreezeMeta @classmethod def freeze(cls, val): cls.frozen = val @classmethod def now(cls): return cls.frozen @classmethod def delta(cls, timedelta=None, **kwargs): """ Moves time fwd/bwd by the delta""" from datetime import timedelta as td if not timedelta: timedelta = td(**kwargs) cls.frozen += timedelta monkeypatch.setattr(datetime, 'datetime', Freeze) Freeze.freeze(original.now()) return Freeze |
也许是偏离主题,但可能会派到其他人来处理这个问题。 这个夹具允许"冻结"时间,然后在你的测试中随意移动它:
1 2 3 4 5 6 7 8 | def test_timesensitive(freeze): freeze.freeze(2015, 1, 1) foo.prepare() # Uses datetime.now() to prepare its state freeze.delta(days=2) # Does something that takes in consideration that 2 days have passed # i.e. datetime.now() returns a date 2 days in the future foo.do_something() assert foo.result == expected_result_after_2_days |
改编自其他答案:
1 2 3 4 5 6 7 8 9 10 11 | import datetime as dt @contextmanager def mocked_now(now): class MockedDatetime(dt.datetime): @classmethod def now(cls): return now with patch("datetime.datetime", MockedDatetime): yield |
使用如下:
1 2 3 | def test_now(): with mocked_now(dt.datetime(2017, 10, 21)): assert dt.datetime.now() == dt.datetime(2017, 10, 21) |