Урок курса

Monkeypatch и mock в pytest: когда что применять

Python для продвинутых: ООП, типизация и тестирование

Тест должен контролировать нестабильные зависимости: текущее время, случайность, переменные окружения и сетевые клиенты. Fixture monkeypatch временно меняет атрибут, словарь, окружение или текущую директорию и автоматически возвращает состояние после теста.

def test_mode_from_env(monkeypatch):
    monkeypatch.setenv("APP_MODE", "test")
    assert read_mode() == "test"

Для объекта можно использовать monkeypatch.setattr(module, "name", replacement). Подменять нужно имя там, где код его ищет, а не обязательно там, где функция была определена изначально. Это частая причина «mock не сработал».

unittest.mock и проверка взаимодействий

Mock и patch умеют задавать возвращаемое значение, выбрасывать исключение и проверять вызовы.

from unittest.mock import Mock

sender = Mock()
sender.send.return_value = "msg-1"

service = NotificationService(sender)
service.notify("hello")

sender.send.assert_called_once_with("hello")

Если интерфейс известен, используйте spec или autospec: тогда опечатка в методе mock не пройдёт незаметно. Для простой зависимости собственный маленький fake или stub часто читается лучше универсального Mock.

Не тестируйте реализацию вместо поведения

Проверка каждого внутреннего вызова делает тест хрупким: безопасный рефакторинг ломает его, хотя внешний результат не изменился. Проверяйте взаимодействие, когда оно и есть контракт — например, платёж отправляется ровно один раз или письмо не уходит при ошибке валидации.

Не допускайте реальную сеть в unit-тестах. Однако бесконечные моки тоже опасны: они подтверждают согласованность теста с собственной фантазией, а не с API провайдера. Дополняйте их контрактными или интеграционными тестами на контролируемой среде.

Короткое правило: monkeypatch удобен для временной замены состояния и имён; Mock — для программируемого collaborator и assertions о вызовах; fake — для более реалистичного поведения без внешнего сервиса.

Попробуйте решить

Где следует patch-ить импортированную функцию?

Продолжить с проверкой и прогрессом

Откройте интерактивный раннер с заданиями урока.

Перейти к интерактивному уроку