Разберите ошибку: почему pytest пропускает методы тестового класса с пользовательским конструктором?
pytest не собирает pytest-style тестовый класс, если в нём определён пользовательский __init__. Такой класс обычно пропускается на этапе сбора с предупреждением PytestCollectionWarning, поэтому его методы не выполняются вообще.
Зависимости для теста следует получать через фикстуры, параметры методов или обычные функции, а не через конструктор тестового класса.
pytest использует соглашения об именовании и автоматический сбор тестов, чтобы тесты не требовали явной регистрации. Для класса это означает, что фреймворк сам создаёт экземпляр без пользовательских аргументов, а затем запускает подходящие методы.
Пользовательский конструктор нарушает это простое правило создания экземпляра: pytest не знает, какие аргументы передавать и как их получать из системы фикстур. Поэтому такие классы намеренно исключаются из обычного pytest-style сбора.
Класс с именем, подходящим под шаблон тестового класса, может выглядеть корректно, но его методы test_... не попадут в запуск. Это опаснее обычного падения теста: проверка может завершиться успешно, хотя часть тестов фактически не выполнялась.
Обычно pytest выводит предупреждение о невозможности собрать класс из-за конструктора. Если предупреждения превращаются в ошибки, сбор завершится с ошибкой; без такой настройки можно не заметить пропуск среди большого вывода.
Для pytest-style класса не следует объявлять собственный __init__. Экземпляр создаётся самим pytest без аргументов, а зависимости передаются тестовым методам или предоставляются через фикстуры.
В этом примере pytest сам создаёт TestReport, видит параметр report у метода и разрешает одноимённую фикстуру. Фикстура может иметь область действия класса, если ресурс должен переиспользоваться методами этого класса, но это не меняет правило создания самого экземпляра.
Если объекту требуется сложная инициализация, варианты зависят от задачи:
setup_method или setup_class для подготовительных действий без конструктора;unittest.TestCase, если класс действительно является unittest-тестом.Важно различать pytest-style классы и классы unittest.TestCase. Последние собираются через специальную совместимость с unittest и имеют собственный жизненный цикл, поэтому правило о пользовательском __init__ для обычного pytest-класса нельзя механически переносить на все тестовые классы.
Также причиной пропуска может быть не только имя класса: должны соблюдаться правила именования класса и методов, если они не изменены настройками pytest. Но изменение шаблонов сбора не устраняет проблему пользовательского конструктора.
Команда добавила конструктор для передачи клиента API в тестовый класс. Запуск завершался без падений, однако отчёт показывал меньше тестов, чем ожидалось; в выводе pytest присутствовало предупреждение о невозможности собрать класс.
Рассматривались три варианта. Передача клиента через конструктор была отвергнута: pytest не управляет такими аргументами. Глобальный клиент тоже не подошёл из-за общего изменяемого состояния и слабой изоляции тестов. В итоге клиент перенесли в фикстуру с нужной областью действия и передавали в методы тестов как параметр.
После этого класс начал корректно собираться, жизненный цикл клиента стал явным, а область действия фикстуры можно было менять без изменения сигнатур конструктора. Дополнительно команда настроила обработку предупреждений как ошибок, чтобы подобный пропуск не оставался незамеченным.
__init__ на setup_method, чтобы тестовый класс начал собираться?Да, если проблема была именно в пользовательском __init__. setup_method вызывается pytest после создания экземпляра перед каждым тестовым методом и не требует аргументов конструктора. Однако зависимости, которыми управляет pytest, всё равно лучше получать через параметры методов или фикстуры; setup_method особенно удобен для простой локальной подготовки.
dataclass?Для pytest важен фактический объект класса, а не способ появления конструктора. Если декоратор сгенерировал пользовательский __init__, pytest-style класс может быть пропущен так же, как класс с явно написанным конструктором. В такой ситуации объект обычно создают внутри фикстуры либо отключают генерацию конструктора, если это совместимо с моделью теста.
Нет, стандартный механизм pytest не внедряет фикстуры в __init__ тестового класса. Фикстуры разрешаются для параметров тестовых функций, методов и самих фикстур, а не для пользовательского конструктора pytest-style класса. Поэтому зависимость следует получать в фикстуре или в параметре тестового метода, после чего при необходимости сохранять её в состояние класса через поддерживаемый жизненный цикл.