Что такое мок-объекты в тестировании и для чего они нужны?
Что проверяют
Понимаете ли вы, зачем изолировать код в тестах и где эта изоляция начинает врать. От Python-разработчика ждут уверенного unittest.mock, а следом спрашивают, куда именно ставить patch и почему тест с моками прошёл, а прод упал.
Как отвечать
Мок это заменитель реальной зависимости, который вдобавок записывает, как с ним взаимодействовали. Полезно назвать семейство тестовых двойников, потому что «моком» часто зовут их всех:
- stub: возвращает заданные ответы и ничего не проверяет;
- fake: упрощённая рабочая реализация, например хранилище в словаре вместо базы;
- spy: пропускает вызовы к настоящему объекту и запоминает их;
- mock: заменяет объект и позволяет проверить вызовы: сколько раз, с какими аргументами.
Зачем нужны: убрать из юнит-теста сеть, платёжный шлюз, почту и текущее время, чтобы тест был быстрым и воспроизводимым.
Инструменты в Python:
unittest.mock:Mock,MagicMockс поддержкой магических методов вроде__enter__,AsyncMockдля корутин, проверки видаassert_called_once_with();patch: декоратор или контекстный менеджер, временно подменяет имя в модуле;patch.objectподменяет атрибут объекта;autospec=Trueилиcreate_autospec(): мок копирует сигнатуры настоящего класса и падает на несуществующем методе или неверных аргументах;- pytest: фикстура
monkeypatch, плагинpytest-mockс фикстуройmocker. Для HTTP естьresponsesподrequestsиrespxподhttpx, для времениfreezegun.
Где спотыкаются
Патчат имя там, где оно определено, а не там, где его ищет код. Если в app/billing.py написано from requests import post, подменять нужно app.billing.post, а patch("requests.post") до этого кода не дотянется.
Создают моки без спецификации. После переименования метода в реальном клиенте тест продолжает зелёным вызывать старое имя, ведь голый Mock принимает любой атрибут. Спасает autospec.
Мокают всё подряд, включая ORM и собственные функции. Тест начинает проверять порядок вызовов вместо результата, ломается от любого рефакторинга и не ловит ошибок в SQL. Базу лучше поднимать настоящую, например через testcontainers.