Проблема нестабильных E2E-тестов не нова. Про флаки, ретраи и «зеленые прогоны» написаны десятки статей, и в каждой есть правильные мысли. Но, как это часто бывает, читать — одно, а заставить это работать в реальном проекте — совсем другое.
Я тоже не искал лёгких путей и пришёл к своим решениям через боль, страдания и разбор бесконечных падений (не повторяйте этот путь, если есть возможность). В этой статье я расскажу, какие подходы помогли нам в команде приблизиться к стабильным E2E-прогонам, которым действительно можно доверять.
Первое, с чего стоит начать — исключить сломанные тесты.
Да, именно так. Нужно исключить все тесты, которые флакают, падают из-за ошибок автотестов или нестабильной среды. Пусть у вас останется один тест, а может не останется ни одного — это нормально. На этом этапе важно не количество, а доверие к результатам.
Будет больно выключать тесты, в которые вы вложили кучу времени и сил. Кажется, будто ты сам себе режешь автоматизацию. Но если тест падает через раз — он уже не выполняет свою основную задачу: давать ответ, всё ли в порядке с системой.
Почему это важно
Тестам, которые регулярно падают без реальных проблем в системе, очень быстро перестают верить.
На их результаты перестают смотреть как на финальное состояние системы — это просто портянка ошибок, которую нужно разбирать, чтобы понять, «что там на самом деле произошло».
А дальше начинается самое неприятное:
автотесты есть, но решения по ним никто не принимает.
Что это даёт на практике
Когда у вас есть пусть маленький, но стабильно зелёный набор E2E-тестов:
ими начинают пользоваться другие члены команды — разработчики, аналитики, менеджеры;
результат тестов можно понять за минуту: зелёное — всё хорошо, красное — проблема в конкретном месте;
такие тесты стали на шаг ближе к встраиванию в CI/CD пайплайн.
Важно: сделать это не разово, а системно
Исключение тестов должно быть не героическим поступком одного автоматизатора, а правилом.
Например:
если тест упал три раза подряд без подтверждённой продуктовой причины — мы исключаем его из основного прогона, помечаем тегом и заводим задачу на исправление.
Без обид, без поисков виноватых — просто гигиена.
Шаг 2. Сделайте ретраи тестов
Чем выше уровень автотестов, тем больше неконтролируемых факторов влияет на результат прогона: сеть, тайминги, очереди, временная недоступность сервисов, асинхронные события. В условиях полной интеграции это нормально, и полностью избавиться от этого невозможно.
Именно поэтому ретраи — не зло и не костыль, а рабочий инструмент.
Зачем нужны ретраи
Перезапуски позволяют отделить реальные проблемы системы от временных сбоев.
Если тест упал один раз и прошёл на повторном запуске — с высокой вероятностью это не баг в продукте, а внешний фактор.
Как это реализовать
В большинстве случаев ретраи можно включить из коробки:
TestNG
JUnit 5
Если вы всё ещё используете JUnit 4 — придётся дописать немного своей логики.
Шаг 3. Научите тесты думать
Очень часто при разборе падений E2E-тестов выясняется:
если бы этот сценарий выполнял человек, он бы спокойно прошёл его руками.
Автотест же в этот момент ведёт себя максимально прямолинейно:
что-то пошло не по плану — всё, тест упал.
Проблема не всегда в системе. Часто проблема в том, что тест слишком быстро сдаётся.
Как “думает” ручной тестировщик
Ручной тестировщик редко следует сценарию как робот.
Если кнопка не появилась — он обновит страницу.
Если форма не открылась — попробует зайти другим путём.
Если действие не сработало — проверит альтернативный вариант.
Он знает обходную логику и применяет её.
Что с этим делать в автотестах
Задача автоматизатора в таких ситуациях — научить тест повторять эту логику.
Это не значит писать сложные конструкции на каждый чих.
Это значит:
уметь проверять несколько допустимых состояний;
корректно обрабатывать альтернативные сценарии;
не падать сразу, если система ведёт себя ожидаемо, но не идеально.
Проще говоря — дать тесту больше контекста, а не заставлять его жить в идеальном мире.
Важное замечание
Здесь легко уйти в крайность и превратить тесты в монстров, которые проходят любой сценарий. Так делать не нужно.
Если система ведёт себя неправильно — тест должен падать.
Но если система ведёт себя допустимо, просто чуть иначе — тест должен понимать это.
Шаг 4. Делайте тесты короче
Чем длиннее E2E-тест, тем больше в нём мест, где он может упасть.
Почему длинные тесты — это боль
Каждый дополнительный шаг — это:
ещё один запрос,
ещё одно ожидание,
ещё одна зависимость от состояния системы.
Даже если каждый шаг по отдельности стабилен, в сумме вероятность падения растёт.
Как мы с этим боролись
Мы перестали пытаться проверять всё и сразу в одном тесте.
Логин проверяется отдельно.
Регистрация проверяется отдельно.
Создание данных — отдельно.
Тесты стали короче, понятнее и предсказуемее.
“Но как это будут понимать ручные тестировщики?”
Этот вопрос возникает почти всегда — и он справедливый.
При разбиении сценариев автотесты перестают выглядеть как классические тест-кейсы.
Мы решали это просто:
создавали папки с названием бизнес-сценария;
внутри хранили тесты, которые проверяют отдельные части этого сценария.
Что это дало
Короткие тесты:
падают реже;
быстрее выполняются;
проще чинятся;
легче воспринимаются;
Без взаимодействия с разработкой тут никуда
Чтобы писать короткие E2E-тесты, часто нужны:
прямые URL до нужных форм или экранов;
ручки для подготовки состояния системы;
возможность обходить лишние шаги UI.
Без помощи разработки это сделать сложно, а иногда невозможно.
Но хорошая новость в том, что эти же инструменты часто сильно упрощают и ручное тестирование.
Шаг 5. Взаимодействуйте с разработкой
Стабильные E2E-тесты невозможно построить в вакууме.
Если автоматизация живёт отдельно от разработки — она почти гарантированно будет нестабильной, медленной и неудобной.
Что автоматизатору действительно нужно от разработки
Разработчики редко думают о тестируемости, если их об этом не просить.
И это нормально — это не их основная задача.
Но автоматизатору могут сильно помочь, например:
прямые URL до нужных экранов и форм в UI;
отдельные
test-onlyэндпоинты для подготовки данных;возможность прокидывать события или управлять их приоритетом;
стабильные HTML-атрибуты или тестовые теги для UI-элементов.
Шаг 6. Используйте моки
E2E-тесты нужны для проверки вашего продукта, а не для валидации всего интернета вокруг него.
Поэтому первое, что стоит сделать, если вы хотите стабильности, — перестать проверять в E2E то, на что вы не можете повлиять.
Что стоит мокать в первую очередь
Внешние зависимости:
сторонние сервисы;
внешние API;
любые интеграции, которые живут за пределами вашего контура.
Если внешний сервис лёг, задеградировал или просто ответил медленнее обычного — это не должно ломать ваши E2E-прогоны.
“Но мы же хотим проверить, что всё работает вместе”
Хотите — проверяйте.
Просто не мешайте эти проверки с основными E2E-сценариями.
Хорошая практика:
один набор тестов — с моками, стабильный, быстрый;
отдельный набор — с реальными интеграциями, реже запускаемый, осознанно нестабильный.
Так вы и интеграции проверите, и основной пайплайн не превратите в лотерею.
Бонус шаг. Запускайте тесты на изолированной среде
Круто, если бы у вас в компании есть возможность поднять изолированную среду, в которой вы сами контролируете версии приложения и внешних интеграций. Среда, в которой никто не накатит, не сломает и не залезет. Но, если честно, есть нюансы:
кто-то должен следить за всеми версиями зависимостей;
кто-то должен поддерживать среду в актуальном виде;
кто-то должен обеспечивать её стабильность.
Вопросов много, а ответов по этому пункту у меня нет. Но не упомянуть такую возможность я не мог.
Для небольшого сервиса и его unit-тестировани или пары микросервисов для интеграционного тестирования такая изоляция работает отлично. А вот системные тесты сюда вписываются сложнее. Если у вас был опыт работы в изолированной среде — велком в комментарии, интересно услышать.
Наверное, я что-то упустил, что-то забыл, но основные пункты, которые мы попробовали и даже те, что не пробовали (см. последний пункт), я описал. Это сработало у нас, сработает и у вас. Пробуйте, экспериментируйте и не бойтесь предлагать новое. Всегда тяжело продвигать изменения туда, где уже устоялись процессы, но чтобы сделать лучше, приходится отказываться от старого.
Всё, что нужно — начать. Маленькими шагами, но регулярно. А дальше вы сами увидите, как это работает и что можно улучшить. Удачи!