I need to test functions which uses datetime.datetime.now(). What is the easiest way to do this?
I need to test functions which uses datetime.datetime.now(). What is the easiest way to do this?
How about using MagicMock(wrap=datetime.datetime) ?
This aproach mocks datetime.datetime.now() but the other methods are available same with the original datetime.datetime.
from unittest.mock import MagicMock
def test_datetime_now(monkeypatch):
import datetime
FAKE_NOW = datetime.datetime(2020, 3, 11, 14, 0, 0)
datetime_mock = MagicMock(wraps=datetime.datetime)
datetime_mock.now.return_value = FAKE_NOW
monkeypatch.setattr(datetime, "datetime", datetime_mock)
assert datetime.datetime.now() == FAKE_NOW
# the other methods are available
assert datetime.datetime.fromisoformat("2020-03-01T00:00:00") == datetime.datetime(2020, 3, 1, 0, 0, 0)
Using @pytest.fixture approach is here.
import datetime
from unittest.mock import MagicMock
import pytest
FAKE_NOW = datetime.datetime(2020, 3, 11, 14, 0, 0)
@pytest.fixture()
def mock_datetime_now(monkeypatch):
datetime_mock = MagicMock(wraps=datetime.datetime)
datetime_mock.now.return_value = FAKE_NOW
monkeypatch.setattr(datetime, "datetime", datetime_mock)
def test_datetime_now2(mock_datetime_now):
assert datetime.datetime.now() == FAKE_NOW
assert datetime.datetime.fromisoformat("2020-03-01T00:00:00") == datetime.datetime(2020, 3, 1, 0, 0, 0)
Adapted from the other answers:
import datetime as dt
from contextlib import contextmanager
from unittest.mock import patch
@contextmanager
def mocked_now(now):
class MockedDatetime(dt.datetime):
@classmethod
def now(cls):
return now
with patch("datetime.datetime", MockedDatetime):
yield
Used like:
def test_now():
with mocked_now(dt.datetime(2017, 10, 21)):
assert dt.datetime.now() == dt.datetime(2017, 10, 21)
If you are a lover of pytest-mock, then mock the datetime.now using this.
from datetime import datetime, timezone
def test_time_now(mocker):
#patch the the datetime method in your file
mock_date = mocker.patch("your_package.your_package.datetime")
FAKE_NOW = datetime(2020, 3, 11, 14, 0, 0, tzinfo=timezone.utc)
mock_date.now.return_value = FAKE_NOW
from your_package.your_package import time_to_test
timestamp_method = time_to_test()
assert timestamp_method == FAKE_NOW
it handly to use unittest.mock.patch as context manager, wright in test:
import datetime
import pytest
from unittest.mock import patch
def test_schedule(schedules_db_client):
faked_now = datetime.datetime(2022, 1, 1, 14, 0, 0)
with patch("datetime.datetime") as mock_datetime:
mock_datetime.now.return_value = faked_now
assert schedules_db_client.get_current_attendant()
Yet another recipe, using pytest-mock with an explicit MagicMock to wrap only the now method:
from datetime import datetime
from my_module import fn_returning_datetime_now
def test_datetime(mocker):
NOW = dt.datetime(1999,1,1)
mock_datetime = mocker.MagicMock(wraps=datetime)
mock_datetime.now.return_value = NOW
mocker.patch("my_module.datetime", mock_datetime)
assert fn_returning_datetime_now == NOW
This is just a variation on other answers here, using mocker.patch instead of monkeypatch.