Mock'ирование datetime.date.today() в Python: решение проблемы
Пройдите тест, узнайте какой профессии подходите
Быстрый ответ
Для мока функции datetime.date.today()
, используйте метод unittest.mock.patch
непосредственно в классе date, который импортирован в модуле, подвергающемся тестированию. Вот пример применения:
from unittest.mock import patch
from datetime import date
import my_module
with patch('my_module.date.today') as mock_today:
mock_today.return_value = date(2023, 1, 1)
# После замены функции datetime.date.today() my_module ‘считает’, что сегодня 1 января 2023 года
В этом контексте, вместо запроса реального текущего времени функция my_module.date.today()
будет возвращать заданный объект date
, обеспечивая тем самым предсказуемость тестов.
Углубляемся в использование моков
unittest.mock.patch
все мы знаем и любим, но есть и другая отличная библиотека, заслуживающая вашего внимания: freezegun.
Расслабляемся с freezegun 🧊⏲️
Основная задача, которую решает Freezegun, — это управление временем. Для установки библиотеки выполните pip install freezegun
. Декоратор @freeze_time("ГГГГ-ММ-ДД")
позволяет провести путешествие во времени:
from freezegun import freeze_time
import my_module
@freeze_time("2023-01-01")
def test_something():
assert my_module.some_function() == expected_result # Теперь мы можем проверять функции, которые зависят от времени
Freezegun заставляет время остановиться, фиксируя его значение во всех модулях, что очень полезно при тестировании.
MagicMock: коллега Patch
Когда работа идёт с изменяющимися датами, unittest.mock.MagicMock
сможет добавить ваших тестам немного магии:
from unittest.mock import patch, MagicMock
from datetime import datetime, timedelta
with patch('my_module.date.today', new_callable=MagicMock) as mock_today:
mock_today.side_effect = [datetime.today(), datetime.today() + timedelta(days=1)]
# Сегодня функция вернёт текущую дату, а завтра — дату, смещённую на один день вперёд
Ловушки, на которые следует быть внимательным
Необходимо аккуратно обращаться с импортами:
Мокируем импорты: Заменяйте на мок функцию date.today()
в том модуле, где она используется.
- ✅ Верно: Мокируем `'my_app.my_module.date.today'`
- ❌ Не верно: Мокируем `'datetime.date.today'`
Контролируем выполнение: Проверяйте результаты, чтобы убедиться, что мок работает как задумано.
Ограничиваем область применения моков: Используйте @patch('your_module.datetime')
, чтобы корректно ограничить действие мока и избежать его проникновения за пределы тест-кейсов.
Визуализация
Представим, что вы управляете отображением времени в большом городе:
| Действительное время | Метод | Имитируемое время |
| 📅 **Сегодняшняя дата**| Применение `mock` | 🔄 **Мокируемая дата** |
Вам потребуются правильные инструменты для изменения этого отображения — в данном случае это unittest.mock
:
- 🛠️ **Инструмент**: `mock` из модуля `unittest`
- 📺 **Цель**: `datetime.date.today()`
- ❌ **Проблема**: Дата на экране не меняется
И тогда, когда у вас появится подходящий код:
with mock.patch('my_app.my_module.date.today') as mock_date:
mock_date.return_value = date(2022, 1, 1) # Мы перемещаемся в прошлое и меняем отображаемую дату
assert my_module.function_display_date() == '01 января 2022'
**Результат**: 📅 Экран показывает другую, замоканную дату! Вам не придётся использовать конденсатор потока.
Не забывайте о важности правильного способа импортирования при использовании mock
.
Мокайте как профи: продвинутые советы
Создаем всесторонние моки для взаимосвязанных модулей
Если модули имеют связь, использование Freezegun поможет "заморозить" время сразу для всех модулей.
Мокирование обёрток
Для сохранения оригинального поведения других функций datetime следует использовать аргумент wraps
:
from unittest.mock import patch, MagicMock
from datetime import datetime
def custom_today():
return datetime(2023, 1, 1)
with patch('my_module.datetime', wraps=datetime) as mock_dt:
mock_dt.date.today = MagicMock(side_effect=custom_today)
# Это изменение затронет только сегодняшнюю дату
Тестирование крайних случаев
Не забывайте тестировать такие даты, как последний день месяца или года.
Полезные материалы
- unittest.mock — библиотека для работы с мок-объектами — Документация Python 3.12.2 — официальное руководство по мокированию.
- Понимание использования мок-объектов в Python – Real Python — подробное объяснение работы с моками.
- Мок-объекты в Python: как улучшить юнит-тесты | Toptal® — советы по повышению эффективности юнит-тестирования.
- python – Пытаюсь замокать datetime.date.today(), но не получается – Stack Overflow — обсуждение и решение проблемы с мокированием
datetime.date.today()
. - [Тестирование кода на Python с помощью pytest [Книга]](https://www.oreilly.com/library/view/python-testing-with/9781680502848/) — книга про тестирование при помощи pytest.