Короткий ответ
Mock — это объект-заменитель реальной зависимости (например, внешнего сервиса или БД), который имитирует её поведение и позволяет проверить, как тестируемый код взаимодействовал с этой зависимостью, без реального вызова.
Как это работает подробнее
Библиотека unittest.mock предоставляет класс Mock/MagicMock, у которого любой атрибут или вызов метода автоматически создаёт новый мок и записывает факт вызова вместе с аргументами, не требуя заранее описывать интерфейс заменяемого объекта. Это позволяет позже проверить, был ли вызван нужный метод, с какими параметрами и сколько раз.
Пример кода
testing_example_296.py
from unittest.mock import Mock
def send_welcome_email(mailer, address):
mailer.send(address, subject="Welcome")
def test_send_welcome_email_calls_mailer():
mailer = Mock()
send_welcome_email(mailer, "user@example.com")
mailer.send.assert_called_once_with("user@example.com", subject="Welcome")Что использовать на практике
- Практика. Моки используют там, где реальный вызов дорог, медленен, недетерминирован или недоступен в тестовом окружении: отправка email, обращение к платёжному шлюзу, системные часы, запись в внешний лог-сервис. patch() из unittest.mock подменяет объект на мок только на время теста и автоматически возвращает исходный объект после его завершения.
Подводные камни
- Риск. Мокать слишком много, из-за чего тест перестаёт проверять реальную логику и превращается в проверку того, что мок вызвали — это ложное чувство безопасности без реальной пользы. Забывать, что мок по умолчанию принимает любые аргументы и не проверяет сигнатуру реальной функции, из-за чего тест не замечает несовместимые изменения интерфейса после рефакторинга кода.