Как стандартный режим pytest определяет, какие файлы считать тестовыми?
При стандартном поиске pytest рекурсивно рассматривает файлы, имена которых соответствуют шаблонам test_*.py или *_test.py, начиная с переданного пути либо текущего каталога. Файл с другим именем сам по себе обычно не будет собран, даже если внутри него есть функции, похожие на тесты.
Соглашения об именовании появились как практическая альтернатива ручной регистрации каждого тестового файла. Такой подход уменьшает конфигурацию и делает структуру проекта предсказуемой: разработчик помещает тест в каталог и называет файл по принятому шаблону.
При этом pytest сохраняет возможность изменить соглашения через конфигурацию. Это позволяет адаптировать автоматический поиск к существующему проекту, не переименовывая все файлы.
Если файл назван, например, checks.py, pytest по умолчанию может не включить его в сборку. В результате тесты не упадут — они вообще не будут запущены, что особенно опасно при локальной проверке и в CI.
Обратная проблема возникает при слишком широких шаблонах: в сборку могут попасть вспомогательные модули с функциями, случайно похожими на тесты. Поэтому правила поиска должны быть согласованы со структурой репозитория и проверяться по результатам collection.
По умолчанию pytest ищет Python-файлы с шаблонами test_*.py и *_test.py. После нахождения файла он отдельно применяет правила обнаружения тестовых модулей, классов и функций, поэтому подходящее имя файла ещё не гарантирует, что каждый его объект станет тестом.
Шаблоны файлов можно переопределить параметром python_files в конфигурации pytest. Например:
После такого изменения стандартные шаблоны перестают быть единственным правилом: pytest будет использовать заданные шаблоны. Важно учитывать, что конфигурация действует на область, в которой она найдена, поэтому другой конфигурационный файл или запуск из иной точки проекта может изменить результат.
Путь запуска также имеет значение. Если pytest запустить для конкретного файла или каталога, поиск ограничивается переданным объектом, но имя файла всё равно должно соответствовать правилам сбора, если файл не указан явно как целевой объект запуска.
Надёжная диагностика — посмотреть список собранных тестов в режиме collection. Это позволяет отличить ситуацию «тест не прошёл» от ситуации «тест не был найден». Компромисс стандартных соглашений прост: они удобны и прозрачны, но требуют дисциплины в именовании и контроля конфигурации.
В репозитории тесты назывались check_users.py, но CI запускал pytest без дополнительной конфигурации. Локально разработчики считали, что тесты существуют, однако CI показывал успешную сборку, потому что файл не попадал в collection.
Рассматривались два варианта. Переименовать файлы в test_users.py было проще для новых участников и соответствовало стандартам, но требовало массового изменения путей и импортов. Добавить шаблон check_*.py в конфигурацию было быстрее и сохранило текущую структуру, однако увеличило зависимость проекта от настроек pytest.
Выбрали переименование, потому что проект был новым, а стандартные соглашения не требовали специальной документации. После этого в CI дополнительно проверили список собранных тестов, чтобы ошибка обнаружения не маскировалась успешным завершением команды.
Нет. Подходящее имя файла лишь допускает файл к дальнейшей сборке. Затем pytest применяет правила к содержащимся объектам: обычно функции должны начинаться с test_, а методы тестовых классов — также соответствовать правилам именования; класс обычно должен быть обнаружен как тестовый класс. Поэтому тестовая функция внутри правильно названного файла всё равно может остаться незапущенной из-за собственного имени.
Явно переданный путь позволяет pytest попытаться обработать этот файл, поэтому полагаться на стандартный шаблон имени в такой точечной команде нельзя как на единственную защиту. Однако правила обнаружения объектов внутри файла сохраняются: функции и классы должны подходить под правила pytest или быть явно организованы так, чтобы собираться.
Нужно анализировать результат collection, а не только итоговый код завершения запуска. Если тест не собран, у него нет результата passed или failed; успешный процесс может означать, что pytest не нашёл ни одного подходящего теста. Проверка количества и списка собранных тестов в CI помогает обнаружить переименование файла, ошибочный путь или неподходящую конфигурацию.