Что такое моки и зачем они нужны
Что проверяют
Понимаете ли вы, что мок это инструмент изоляции, и умеете ли вовремя остановиться: тест, в котором замокано всё, проверяет только то, что вы сами же в него и записали. Заодно проверяют знание стандартной библиотеки, а не пересказ определения.
Как отвечать
Мок подменяет зависимость объектом, который возвращает заданное и запоминает вызовы. Термины стоит развести: стаб просто отдаёт данные, мок ещё и позволяет проверить факт и аргументы вызова, фейк это упрощённая рабочая реализация вроде хранилища в памяти.
from unittest.mock import create_autospec
def test_fetch_user():
db = create_autospec(Database, instance=True)
db.get_user.return_value = {"id": 1}
assert fetch_user(db, 1) == {"id": 1}
db.get_user.assert_called_once_with(1)Почему create_autospec, а не голый Mock: у обычного мока есть любой атрибут, поэтому вызов несуществующего метода пройдёт молча. Автоспек сверяет имена и сигнатуры, и тест краснеет там, где должен.
Ещё два пункта, которые отличают опытный ответ. Патчить надо там, где имя ищется, а не там, где объявлено: если модуль сделал импорт функции к себе, патчится путь в этом модуле. Асинхронную зависимость подменяет AsyncMock, обычный мок вернёт не корутину и await упадёт.
Заканчивать лучше границей применимости: моки хороши для внешних систем, времени и случайности, а для своей логики честнее фейк или настоящая база в контейнере.
Где спотыкаются
Мокают то, что тестируют. Подменяют внутренние функции того же модуля, и тест начинает повторять реализацию: любой рефакторинг красит его в красный, а настоящую ошибку он при этом не ловит.
Пишут проверку с опечаткой. Обращение вида called_once_with без префикса assert создаёт очередной дочерний мок и всегда истинно, поэтому тест вечнозелёный. Современные версии ругаются на атрибуты, начинающиеся с assert, но именно такую форму не ловят.
Считают зелёные моки доказательством работающей интеграции. Формат ответа внешнего API изменился, замоканный остался прежним, и падение обнаруживается на проде. Нужен хотя бы один контрактный или интеграционный тест против реального сервиса.