В автотесте код открытия браузера, авторизации и проверок смешан в одном сценарии. Какой архитектурный принцип позволит изменить жизненный цикл запуска, не переписывая проверки?
Следует применить разделение ответственности: вынести управление жизненным циклом и подготовкой окружения в фикстуры или слой оркестрации, действия над системой — в предметные объекты, а проверки — в отдельные утверждения сценария. Тогда изменение способа запуска, авторизации или очистки состояния не затронет бизнес-проверки.
Важно разделять не каждый шаг механически, а изменения по их причинам. Код, который меняется из-за инструмента или инфраструктуры, не должен быть смешан с кодом, который описывает проверяемое поведение.
По мере роста набора автотестов в сценариях начинают повторяться открытие браузера, создание клиентов, авторизация, подготовка данных и очистка состояния. Первоначально это удобно: тест выглядит самодостаточным и быстро создаётся.
Но при изменении окружения или инструмента одинаковые фрагменты приходится исправлять во множестве мест. Разделение ответственности возникло как практический способ уменьшить дублирование и локализовать изменения в больших тестовых наборах.
Если сценарий одновременно управляет браузером, создаёт тестовые данные, выполняет действия пользователя и проверяет результат, он связан сразу с несколькими уровнями системы. Изменение жизненного цикла браузина, способа авторизации или транспорта API приводит к массовым правкам.
Такая связанность повышает стоимость сопровождения и скрывает причину падения. Например, ошибка подготовки окружения может выглядеть как ошибка бизнес-проверки, а неудачная очистка данных — как дефект приложения.
Полная изоляция каждого фрагмента также опасна: чрезмерные абстракции делают тесты трудными для чтения и могут скрыть реальные действия. Целью является не максимальное количество слоёв, а локализация изменений и сохранение понятного сценария.
Обычно выделяют несколько зон ответственности:
Связь между слоями должна быть направлена сверху вниз: сценарий использует действия и проверки, а действия используют технические адаптеры. Сценарий не должен напрямую зависеть от низкоуровневых локаторов, деталей HTTP-транспорта или конкретного способа создания сессии.
Подготовка данных должна быть явной и предсказуемой. Если фикстура автоматически делает слишком много действий, тест становится труднее понять; если подготовка полностью копируется в сценариях, возвращается дублирование. Компромисс — общие фикстуры для инфраструктурных операций и явные фабрики или шаги для значимых бизнес-данных.
Такое разделение не гарантирует стабильность само по себе. Оно лишь создаёт места, где можно централизованно реализовать ожидания, повторное использование сессий, очистку, журналирование и замену инструмента. Стабильность по-прежнему зависит от детерминированных данных, корректных ожиданий и независимости тестов.
Команда имела несколько десятков сценариев, в каждом из которых вручную запускался браузер, выполнялась авторизация и затем проверялось оформление заказа. После перехода на другой механизм управления сессиями пришлось изменять каждый тест, а часть сценариев стала завершаться с незакрытыми ресурсами.
Рассматривались три варианта. Первый — оставить тесты самодостаточными: это упрощает локальный запуск, но сохраняет дублирование и высокую стоимость изменений. Второй — сделать один большой базовый класс со всей логикой: это сокращает повторение, но создаёт скрытые зависимости и усложняет понимание порядка подготовки.
Выбрали фикстуру жизненного цикла, отдельный объект действий оформления и независимые проверки результата. Фикстура стала единственным местом управления сессией, а сценарии сохранили читаемую последовательность предметных действий.
В результате смена механизма авторизации потребовала изменения фикстуры, а не всех сценариев. При этом тесты не стали полностью изолированными от технических деталей: для диагностики сохранили доступ к журналам и идентификаторам созданных ресурсов через явно передаваемый контекст.
1. Достаточно ли вынести повторяющийся код в общий базовый класс?
Нет. Вынос кода уменьшает дублирование, но не обязательно разделяет ответственности. Базовый класс может скрыть порядок инициализации, неявно создавать состояние и связывать все тесты с одной иерархией.
Предпочтительнее композиция: сценарий получает нужные фикстуры, фабрики и объекты действий явно. Наследование допустимо для действительно общего технического жизненного цикла, но не должно превращаться в контейнер всех вспомогательных операций.
2. Где должны находиться проверки — внутри объектов страниц или в сценариях?
Технические проверки состояния конкретного элемента могут находиться рядом с объектом страницы, если они описывают его интерфейс, например доступность операции или наличие сообщения. Бизнес-утверждения лучше оставлять на уровне сценария, чтобы было видно, какое правило проверяется.
Если объект страницы содержит все бизнес-проверки, он становится трудно переиспользуемым и начинает смешивать представление с предметной логикой. Если сценарий напрямую знает все локаторы, любое изменение интерфейса массово распространяется по тестам.
3. Не приведёт ли такое разделение к чрезмерному количеству абстракций?
Может привести, если создавать отдельный слой для каждого действия без самостоятельной ответственности или скрывать простой тест за длинной цепочкой обёрток. Признак избыточности — чтобы понять один сценарий, приходится переходить через множество файлов и восстанавливать неявный порядок вызовов.
Границу следует проводить по причинам изменения: жизненный цикл, техническое взаимодействие, предметное действие и проверка должны разделяться, если они развиваются независимо. Для простого теста допустима компактная структура; архитектура должна расти вместе с реальным дублированием и связностью, а не опережать их.