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
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
- It is often better to patch the module under test rather than the datetime package directly. See also where to patch.
- We expect the date time value to be returned, not the mock object (which is what your assertion expects, I think).
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
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
- It is often better to patch the module under test rather than the datetime package directly. See also where to patch.
- We expect the date time value to be returned, not the mock object (which is what your assertion expects, I think).