Mock datetime.datetime.now() while unit testing

Viewed 6200
@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)

I am looking to mock datetime.datetime.now() which is called in the send_new_email method. I am unsure how to do it however.

I tried creating a new datetime object

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

and then overriding datetime.datetime.now

datetime.datetime.now = MagicMock(return_value=datetime_object)

However, I get the error

TypeError: can't set attributes of built-in/extension type 'datetime.datetime'

This question was marked as duplicate of Python: Trying to mock datetime.date.today() but not working

Python: Trying to mock datetime.date.today() but not working

I had already tried this solution but I could not get it to work. I cannot install freezegun due to the project requirements.

I have created a new class in the test file

class NewDate(datetime.date):
@classmethod
def today(cls):
    return cls(2010, 1, 1)
datetime.date = NewDate

But I have no idea how to get the SendEmails class to use this.

1 Answers

You could replace the whole class:

_FAKE_TIME = 0
class _FakeDateTime(datetime.datetime):
    @staticmethod
    def now():
        return _FAKE_TIME

then to use it:

_FAKE_TIME = whatever
datetime.datetime = _FakeDateTime

The class needs some refinements like comparison operators to make a FakeDateTime comparable to a datetime, but it should work.

Related