В тестовом проекте helper импортируют из другого test-модуля: какой главный риск создаёт такая организация?
Главный риск — скрытая зависимость тестов от внутреннего устройства другого тестового модуля. При его импорте выполняется верхнеуровневый код, а изменение имени, расположения или режима импорта может сломать несвязанные тесты ещё до их запуска.
Общие функции следует выносить в обычный вспомогательный модуль, а pytest-фикстуры — в подходящий conftest.py. Тогда код поддержки не участвует в сборке как тестовый модуль и имеет явно определённое назначение.
Тестовые фреймворки отделяют код проверки от кода, который подготавливает данные и окружение. Это разделение появилось из практической необходимости повторно использовать подготовку без копирования и не связывать тесты с порядком выполнения других тестов.
В pytest тестовые файлы дополнительно проходят сборку: фреймворк находит их по соглашениям об именах, импортирует и анализирует содержащиеся в них тесты. Поэтому тестовый модуль является прежде всего единицей обнаружения тестов, а не стабильной библиотекой общих компонентов.
Если один test_-модуль импортирует helper из другого, между ними возникает неявная связь. Импорт может выполнить побочные действия верхнего уровня, подтянуть лишние зависимости или привести к конфликтам имён и различиям поведения при запуске из разных инструментов.
Особенно опасно, когда helper случайно зависит от глобального состояния другого тестового файла. Тогда порядок импорта, повторный запуск тестов и параллельное выполнение способны давать разные результаты.
Общие чистые функции и классы размещают в обычном модуле поддержки, например в tests/support/factories.py. Он не должен соответствовать шаблонам тестовых файлов, поэтому pytest не будет рассматривать его как набор тестов.
Фикстуры, которые должны автоматически находиться тестами в определённой части дерева, обычно размещают в conftest.py. Их не требуется импортировать вручную: pytest подключает фикстуры по области видимости каталога. Однако conftest.py не стоит превращать в универсальную библиотеку обычных функций: для таких функций лучше использовать явный импорт из обычного модуля.
Минимальная безопасная структура может выглядеть так:
В этом варианте test_orders.py использует фабрику из support, а фикстуры получает через механизм pytest. Поддерживающий код не зависит от того, какой другой тестовый файл был импортирован первым.
Вынесение helper в обычный модуль не устраняет все проблемы автоматически: сам helper всё равно должен избегать глобального изменяемого состояния и побочных эффектов при импорте. Компромисс состоит в том, что явные импорты требуют немного больше кода, зато зависимости становятся видимыми и проще контролируются.
В проекте несколько тестов заказов импортировали фабрику из test_users.py. После переименования этого файла pytest перестал собирать часть тестов: ошибка возникала на этапе импорта, хотя сами тесты заказов логически не зависели от пользовательских тестов.
Рассматривались два варианта. Можно было оставить импорт и добавить совместимый модуль-переадресацию, но это сохранило бы скрытую связь и увеличило технический долг. Можно было поместить фабрику в conftest.py, но тогда обычная функция стала бы зависеть от правил обнаружения pytest и её было бы неудобно использовать вне тестового запуска.
Выбрали отдельный модуль tests/support/factories.py, а фикстуры оставили в conftest.py. После этого переименование тестовых файлов не влияло на импорт фабрик, ошибки зависимостей стали видны непосредственно в месте использования, а код подготовки данных можно было переиспользовать в других тестовых инструментах.
importlib риск импорта helper из другого тестового файла?Нет. Режим импорта может изменить правила разрешения имён и загрузки тестовых модулей, но не превращает тестовый файл в стабильный модуль поддержки. Верхнеуровневый код и скрытые зависимости всё равно остаются проблемой, поэтому helper следует вынести в обычный модуль.
Нет. Фикстура нужна, когда pytest должен управлять подготовкой, областью действия, зависимостями или очисткой ресурса. Чистую функцию-фабрику, преобразователь данных или объект без жизненного цикла лучше оставить обычной функцией и импортировать явно.
Если файл соответствует шаблону тестов, pytest может включить его в коллекцию и импортировать при сборке. Переименование способно изменить и факт обнаружения файла, и путь, по которому он импортируется; поэтому тестовые модули нельзя надёжно использовать как внутренний API проекта.