Как реализовать тестирование микросервисов, включая юнит и интеграционные тесты?
Что проверяют
Умеете ли вы строить тесты сервиса на Python так, чтобы юниты были быстрыми, а интеграция проверяла настоящие зависимости. Следом спрашивают, как вы мокаете внешние HTTP-вызовы и чем поднимаете базу в тестах.
Как отвечать
Раскройте уровни и конкретные инструменты:
- юнит-тесты:
pytestс фикстурами и@pytest.mark.parametrize, моки черезunittest.mockилиpytest-mock. Бизнес-логику полезно отделять от фреймворка, тогда её можно тестировать без HTTP и базы; - тесты API сервиса: в FastAPI
TestClientилиhttpx.AsyncClientсASGITransport, зависимости подменяются черезapp.dependency_overrides. В Django это тестовый клиент иpytest-django. Для асинхронного кода нуженpytest-asyncioили плагинanyio; - внешние HTTP-вызовы:
respxдляhttpx,responsesдляrequests. Так проверяются тайм-ауты, ретраи и ответ 503 от соседнего сервиса; - интеграционные тесты: настоящие PostgreSQL, Redis, Kafka или RabbitMQ через
testcontainers. Схема накатывается миграциями Alembic, каждый тест работает в транзакции, которая откатывается в конце; - контрактные тесты:
pact-pythonфиксирует ожидания потребителя, а поставщик проверяет себя по этим контрактам в своём CI.
Организация: каталоги tests/unit и tests/integration, маркер @pytest.mark.integration, чтобы запускать наборы раздельно. Юнит-тесты гоняются на каждый коммит, интеграционные на merge request; pytest-xdist распараллеливает прогон, pytest-cov показывает непокрытые ветки. Покрытие стоит воспринимать как подсказку, где нет тестов, а не как цель.
Где спотыкаются
Патчат не там. mock.patch должен указывать место, где имя ищется при вызове, а не где функция объявлена: patch("app.service.send_email"), а не patch("app.email.send_email"), если сервис сделал from app.email import send_email.
Подменяют PostgreSQL на SQLite ради скорости. Отличаются типы, JSONB, блокировки и поведение транзакций, и тесты пропускают ошибки, которые проявятся только в проде.
Оставляют общее состояние между тестами: данные в базе, глобальные объекты, незакрытые клиенты. Тесты начинают зависеть от порядка и падают только при параллельном прогоне.