单元测试时模拟 datetime.datetime.now()

use*_*855 6 python datetime

@pytest.mark.parametrize("test_input,expected_output", data)
def test_send_email(test_input, expected_output):
    emails = SendEmails(email_client=MagicMock())
    emails.send_email = MagicMock()
    emails.send_new_email(*test_input)
    emails.send_email.assert_called_with(*expected_output)
Run Code Online (Sandbox Code Playgroud)

我正在寻找模拟在 send_new_email 方法中调用的 datetime.datetime.now() 。不过我不确定该怎么做。

我尝试创建一个新的日期时间对象

 datetime_object = datetime.datetime.strptime('Jun 1 2017  1:33PM', 
                                          '%b %d %Y %I:%M%p')
Run Code Online (Sandbox Code Playgroud)

然后覆盖 datetime.datetime.now

datetime.datetime.now = MagicMock(return_value=datetime_object)
Run Code Online (Sandbox Code Playgroud)

但是,我收到错误

类型错误:无法设置内置/扩展类型“datetime.datetime”的属性

这个问题被标记为 Python 的重复:尝试模拟 datetime.date.today() 但不起作用

Python:尝试模拟 datetime.date.today() 但不起作用

我已经尝试过这个解决方案,但无法让它发挥作用。由于项目要求,我无法安装 freezegun。

我在测试文件中创建了一个新类

class NewDate(datetime.date):
@classmethod
def today(cls):
    return cls(2010, 1, 1)
datetime.date = NewDate
Run Code Online (Sandbox Code Playgroud)

但我不知道如何让 SendEmails 类使用它。

小智 1

你可以替换整个班级:

_FAKE_TIME = 0
class _FakeDateTime(datetime.datetime):
    @staticmethod
    def now():
        return _FAKE_TIME
Run Code Online (Sandbox Code Playgroud)

然后使用它:

_FAKE_TIME = whatever
datetime.datetime = _FakeDateTime
Run Code Online (Sandbox Code Playgroud)

该类需要一些改进,例如比较运算符,以使 FakeDateTime 与日期时间相当,但它应该可以工作。