Mocking datetime.now using pytest-mock

Question:

I have a function func_to_mock in module module_to_mock.py. My unit test is located in test_func_to_mock.py

I am trying to mock datetime.datetime.now, however, I am struggling. I get the error TypeError: cannot set 'now' attribute of immutable type 'datetime.datetime'.

What am I missing here?

module_to_mock.py:

# module_to_mock.py

import datetime


def func_to_mock() -> datetime.datetime:
    return datetime.datetime.now()

My unit test:

# test_func_to_mock.py

import datetime

from pytest_mock import MockFixture

import port_bt.module_to_mock


def test_func_to_mock(mocker: MockFixture) -> None:
    # This will error with:
    # TypeError: cannot set 'now' attribute of immutable type 'datetime.datetime'
    mocked_date = mocker.patch(
        "datetime.datetime.now", return_value=datetime.datetime(2023, 1, 31, 0, 0, 0)
    )

    assert port_bt.module_to_mock.func_to_mock() == mocked_date
Asked By: Andi

||

Answers:

As you’ve seen, you cannot patch Python standard library classes that are implemented in C (according to these unittest.mock docs). However, you can patch the datetime package like so:

test_func_to_mock.py

import datetime
from pytest_mock import MockFixture

import module_to_mock


def test_func_to_mock(mocker: MockFixture) -> None:

    mocked_datetime = mocker.patch(
        "module_to_mock.datetime",  # 1
    )
    jan_31 = datetime.datetime(2023, 1, 31, 0, 0, 0)
    mocked_datetime.datetime.now.return_value = jan_31

    assert module_to_mock.func_to_mock() == jan_31 # 2

Note that

  1. It is often better to patch the module under test rather than the datetime package directly. See also where to patch.
  2. We expect the date time value to be returned, not the mock object (which is what your assertion expects, I think).
Answered By: FiddleStix
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.