Как получать логи от тестируемого компонента
Что проверяют
Умеете ли вы перехватывать логи внутри теста и проверять их утверждениями, а не читать файл глазами после прогона. Для Python ждут caplog из pytest или assertLogs из unittest. Следом часто спрашивают, как достать логи компонента, который работает в отдельном процессе или контейнере.
Как отвечать
Разберите по тому, где живёт компонент:
- тот же процесс, pytest: фикстура
caplog. Вызовcaplog.set_level(logging.WARNING, logger="app.billing")задаёт уровень, дальше проверяетеcaplog.records(у записи естьlevelname,getMessage(),exc_info) илиcaplog.record_tuples. Чтобы видеть логи прямо во время прогона, включаютlog_cli = trueв конфиге pytest; - тот же процесс, unittest:
self.assertLogs("app.billing", level="ERROR")возвращает объект сoutputиrecords, аassertNoLogs(с Python 3.10) проверяет, что лишнего не написано; - вывод через
print:capsysдляsys.stdoutиsys.stderr,capfd, если пишут на уровне файловых дескрипторов; - отдельный процесс:
subprocess.run(..., capture_output=True, text=True)и разборstdoutиstderr; - контейнер в интеграционном тесте: логи берут через Docker API, в testcontainers это метод
get_logs()у контейнера. Удобнее, если сервис пишет JSON: тогда проверяются поля, а не подстроки.
Условие для всего этого: компонент получает логгер через logging.getLogger(__name__) и сам обработчики не настраивает. Конфигурация логирования принадлежит приложению и тестам, а не модулю.
Где спотыкаются
Вызывают logging.basicConfig внутри компонента и пишут в файл. В тестах это даёт гонки за файл и мусор на диске, а повторный basicConfig молча ничего не делает, если у корневого логгера уже есть обработчики.
Ставят логгеру propagate = False и удивляются пустому caplog. Фикстура вешает обработчик на корневой логгер, и записи, которые до него не всплывают, в перехват не попадают.
Сверяют весь текст через caplog.text. Любая правка формулировки ломает тест, надёжнее проверять уровень, имя логгера и ключевую часть записи.