Вступление

Когда в компании начинают выстраивать автоматизацию тестирования, чаще всего обсуждают инструменты, фреймворки, CI/CD, архитектуру тестов и покрытие. Но заметно реже задают более приземлённый вопрос: а что вообще не стоит автоматизировать?

На практике далеко не каждый сценарий, который технически можно покрыть автотестом, имеет смысл покрывать. Где-то автоматизация действительно ускоряет релизный цикл и снижает объём ручной рутины. А где-то, наоборот, превращается в постоянный источник затрат: тест долго пишется, нестабильно работает, требует регулярной отладки и в итоге обходится бизнесу дороже, чем ручная проверка.

В этой статье я предлагаю посмотреть на автоматизацию тестирования не только с инженерной, но и с инвестиционной точки зрения. Не как на «красиво написанный автотест», а как на вложение ресурсов, которое должно окупаться. У любого такого вложения есть цена: разработка, поддержка, расследование падений, адаптация к изменениям продукта, время инженеров и стоимость инфраструктуры. И если всё это не даёт ощутимой отдачи, то, возможно, автоматизировать такой сценарий просто невыгодно.

Ниже — практический список ситуаций и типов проверок, для которых автоматизация часто оказывается плохой инвестицией. Это наблюдений из реальной практики, к которому можно вернуться, когда снова возникнет вопрос: стоит ли автоматизировать конкретный сценарий.

Почему не всё, что можно автоматизировать, нужно автоматизировать

Автоматизация тестирования нужна затем, чтобы уменьшать объём ручной рутины и ускорять релизный цикл. Логика понятная: чем быстрее команда получает обратную связь, тем быстрее можно поставлять изменения пользователю. На этом уровне всё выглядит просто: написал автотест, убрал ручную проверку, сэкономил время.

Проблема в том, что такая логика почти всегда слишком упрощённая.

Частая ошибка — оценивать выгоду автоматизации только по времени одного прогона. Если ручная проверка занимает 60 минут, а автотест выполняет тот же сценарий за 30, возникает ощущение, что мы сразу получили двукратное ускорение. Но бизнесу важно не время одного запуска, а полная стоимость такого решения.

У любого автотеста есть цена: его нужно разработать, встроить в существующий процесс, поддерживать в актуальном состоянии, расследовать падения, адаптировать к изменениям продукта и окружения. И если сценарий сам по себе тяжёлый, долгий и нестабильный, то эта цена быстро становится выше потенциальной выгоды.

Хороший пример — проверка обновления системы с версии v1 на v2 через загрузку бинарного файла. Сам сценарий большой, многошаговый, содержит несколько асинхронных состояний и легко занимает 20–30 минут, а иногда и дольше. На первый взгляд это идеальный кандидат на автоматизацию: ручной прогон долгий, значит автотест должен дать заметную экономию.

Но именно на таких сценариях чаще всего ломается наивная математика.

Чтобы такой тест был реально полезным, нужно, чтобы он был не просто автоматическим, а ещё и стабильным. На практике у подобных кейсов обычно много точек отказа: сеть, загрузка файла, рендеринг UI, тайминги, доступность стенда, перезапуск сервиса, восстановление соединений, состояние инфраструктуры. В итоге вместо предсказуемого инструмента команда получает тяжёлый тест, который регулярно падает и требует ручного разбора.

Теперь посчитаем это не на уровне ощущений, а на уровне простой экономики.

Допустим, ручная проверка занимает 1 час. Автотест — 30 минут. Сценарий запускается один раз в две недели. На разработку теста уходит 5 рабочих дней. Дальше добавим сопровождение: 1 день в месяц на поддержку и ещё 1 день в месяц на разбор флаков и нестабильных падений. Для простоты примем, что час работы Manual QA стоит 1 условную единицу, а час работы AQA — 1.5.

Тогда картина будет такой:

Упрощённая экономика сценария

Параметр

Ручная проверка

Автотест

Время одного прогона

1 час

0.5 часа

Частота запуска

2 раза в месяц

2 раза в месяц

Прогоны за 12 месяцев

24

24

Время на прогоны за год

24 часа

12 часов

Первоначальная разработка

0 часов

40 часов

Поддержка за год

0 часов

96 часов

Разбор падений за год

0 часов

96 часов

Итого трудозатраты за год

24 часа

244 часа

Если перевести это в условные деньги:

Стоимость за 12 месяцев

Статья затрат

Ручная проверка

Автотест

Прогоны

24 × 1 = 24

12 × 1.5 = 18

Разработка

0

40 × 1.5 = 60

Поддержка

0

96 × 1.5 = 144

Разбор падений

0

96 × 1.5 = 144

Итого за год

24

366

И это при довольно оптимистичных вводных: без учёта инфраструктурных инцидентов, переписывания теста после заметных изменений UI и скрытых затрат на переключение контекста.

На уровне одного запуска автотест действительно выглядит лучше: 30 минут вместо 60. Но на горизонте года экономия на прогонах составляет всего 6 условных единиц, а полная стоимость владения тестом — 366. То есть ROI такого решения уходит глубоко в минус.

Именно поэтому вопрос «можно ли это автоматизировать?» сам по себе слишком слабый. Правильный вопрос другой: окупится ли такая автоматизация вообще?

Если сценарий запускается редко, долго выполняется, зависит от большого числа внешних факторов и требует постоянного ручного разбора, то автоматизация легко превращается в убыточную инвестицию. Формально тест есть. По факту команда получила не ускорение, а дорогой актив с отрицательной доходностью.

Именно из таких кейсов и рождается очень дорогая автоматизация тестирования, которая не снижает затраты бизнеса, а начинает их системно увеличивать.

1. Недетерминированный результат

Один из самых плохих кандидатов на автоматизацию — сценарий, в котором заранее не определён точный ожидаемый результат. Как только тест перестаёт проверять чёткое и воспроизводимое ожидание, он начинает не верифицировать систему, а угадывать её поведение. А угадайка — это почти всегда путь к флакам, ложным падениям и бессмысленной поддержке.

Смысл автотеста в том, чтобы быстро и однозначно ответить на вопрос: система работает правильно или нет. Если сам ожидаемый результат размыт, плавает или зависит от скрытой логики, тест теряет ценность. Он может падать на корректном поведении системы и, наоборот, проходить там, где проблема реально есть.

Простой пример — банковский процесс, в котором система назначает дату платежа по кредитному счёту. Допустим, день платежа выбирается по внутренним правилам и в ряде случаев может случайным или полурандомным образом смещаться на следующий месяц. Если в таком сценарии автотест жёстко проверяет конкретный день, он начинает зависеть не от бизнес-результата, а от детали, которая изначально не гарантирована. В результате тест будет то зелёным, то красным, хотя продукт может работать в рамках допустимой логики.

Что здесь делать правильно? Не пытаться зафиксировать то, что сама система не обещает фиксировать. Если бизнес-правило гарантирует только месяц и год, значит именно это и нужно проверять. Не день, не конкретное число в календаре, а тот уровень точности, который действительно зафиксирован требованиями и поведением системы. Иначе автотест будет проверять не контракт системы, а ваши ожидания от неё.

Та же проблема часто встречается и в API. Например, сервис возвращает список элементов, но порядок элементов в ответе не гарантирован. Если тест сравнивает массив целиком и ожидает жёсткую сортировку там, где контракт её не обещает, то такой тест изначально написан неверно. Он снова начинает играть в угадайку: сегодня данные пришли в одном порядке, завтра — в другом, и оба варианта при этом могут быть корректными.

Это не значит, что такой кейс нельзя автоматизировать вообще. Это значит, что его нужно автоматизировать правильно. Если порядок не важен, нужно сравнивать состав данных, а не их позицию. Если важно наличие конкретного элемента, нужно проверять именно его наличие и корректность его полей. Если список слишком динамический, возможно, тест стоит сузить до одного контролируемого объекта, а не пытаться валидировать весь ответ целиком.

Это важный принцип: если результат недетерминирован, нужно не отказываться от автоматизации автоматически, а уменьшать зону проверки до детерминированной части.

На практике здесь хорошо работает несколько вопросов:

  • Что именно система гарантирует всегда?

  • Что в этом сценарии является стабильным инвариантом?

  • Что из результата действительно важно для бизнеса, а что является побочным эффектом реализации?

  • Можно ли проверить не весь объект целиком, а только ту часть, которая обязана быть неизменной?

Поэтому главный вывод здесь простой: нельзя надёжно автоматизировать то, что не имеет чёткого и стабильного ожидаемого результата. Если результат плавающий, сначала нужно найти в нём детерминированную часть. Если такой части нет, то автоматизация, скорее всего, превратится в бесконечную борьбу с ложными падениями.

Иными словами, хороший автотест проверяет инвариант. Плохой — пытается угадать текущее состояние системы.

2. Долгие процессы

Если в предыдущем пункте проблема была в недетерминированности результата, то здесь ситуация другая: результат может быть вполне однозначным, но сам сценарий слишком длинный и перегруженный шагами.

Долгий тест — это не просто медленный тест. Обычно это цепочка из большого количества действий, зависимостей и промежуточных состояний. А значит, и точек отказа в нём тоже много. Такой сценарий может падать не из-за дефекта в продукте, а из-за сети, таймингов, UI, внешних интеграций, очередей, почты или нестабильного окружения.

Как практическое правило: если тест выполняется дольше минуты и проходит через несколько крупных шагов, это уже повод задуматься, нужно ли вообще тащить его целиком в один E2E. Часто такой сценарий правильнее разрезать, упростить, изолировать или перенести ниже — на API, CLI, компонентные или контрактные проверки.

Почему это важно? Потому что длина теста почти всегда напрямую связана с количеством точек отказа.

Представим типичный «тест-монстр»: регистрация пользователя, ожидание письма, получение OTP-кода, ввод подтверждения, создание сущности, ожидание публикации, повторная проверка почты, проверка события в Kafka. Формально это один бизнесовый сценарий. По факту — цепочка из UI, почты, фоновых процессов, асинхронных джоб и внешних интеграций. Такой тест начинает зависеть сразу от всего.

И здесь важно понимать простую математику. Если в тесте 5 последовательных шагов, и каждый из них успешен в 95% случаев, то вероятность успешного прохождения всего теста будет не 95%, а: 0.95 × 0.95 × 0.95 × 0.95 × 0.95 ≈ 77%

Если шагов уже 10, то: 0.95^10 ≈ 60%

А если отдельные шаги проходят не в 95%, а в 90% случаев, то картина ещё хуже: 0.9^10 ≈ 35%

То есть даже если каждый отдельный шаг выглядит «в целом стабильным», длинная цепочка очень быстро превращает тест в лотерею. Сегодня зелёный, завтра красный, послезавтра снова зелёный — и каждый раз нужно разбираться, это реальная регрессия или просто накопленный статистический шум.

Для наглядности:

Количество шагов

Успех каждого шага

Успех всего теста

5

95%

77%

10

95%

60%

10

90%

35%

Обычно такую конструкцию пытаются лечить sleep-ами, ожиданиями, ретраями и дополнительной синхронизацией. Но это почти всегда маскировка проблемы, а не решение. Тест становится ещё медленнее, ещё тяжелее и ещё дороже в сопровождении.

У длинных сценариев есть и вторая проблема: дорогая обратная связь. Если тест выполняется 15–20 минут, любая отладка превращается в затяжной цикл. Изменили одну строчку — ждёте. Перезапустили — ждёте снова. Хотите локализовать проблему — прогоняете весь сценарий заново. В итоге растёт стоимость каждой итерации, и команда начинает обслуживать сам тест вместо того, чтобы получать от него пользу.

Поэтому проблема долгих тестов не только во времени прогона. Вместе с длиной растёт и стоимость владения: дольше ждать результат, дольше разбирать падение, дольше отлаживать, дольше перепроверять, сложнее отделять продуктовую проблему от инфраструктурного шума.

Главный вывод здесь простой: чем длиннее тест, тем выше шанс, что вы автоматизируете не проверку, а будущую боль команды. Если сценарий тяжёлый, многошаговый и медленный, его почти всегда лучше дробить, изолировать или переносить на другой уровень. Иначе окупаемость такой автоматизации снова уйдёт в минус.

3. Сценарии с хрупкой автоматизацией

Есть отдельный класс сценариев, где результат сам по себе может быть вполне детерминированным, но проблема в другом: способ автоматизации получается слишком хрупким, дорогим и плохо управляемым.

Хороший пример — работа с canvas в вебе. На канве что-то рисуется, двигается, приходит стримом с бэка, обновляется в реальном времени. Формально пользовательский сценарий может быть понятным: открыть экран, дождаться отрисовки объекта, кликнуть по нужному элементу, проверить реакцию системы. Но с точки зрения автоматизации всё резко усложняется.

Проблема в том, что у canvas часто нет нормальной семантики интерфейса, за которую может зацепиться тест. Нет стабильных локаторов, нет предсказуемой DOM-структуры, нет удобных атрибутов. В итоге тест вынужден работать почти на уровне пикселей: кликать в координаты, угадывать область объекта, подстраиваться под размеры экрана, масштаб, плотность пикселей, скорость рендера и момент, когда элемент вообще появился на канве.

А дальше начинается типичная история хрупкой автоматизации. Изменилось разрешение браузера — тест сломался. Сдвинули объект на несколько пикселей — тест сломался. Сделали редизайн или поменяли масштабирование — тест сломался. Канва дорисовалась чуть позже обычного — тест снова сломался. И каждый такой случай будет требовать не анализа продукта, а очередного ремонта самого теста.

Это важное отличие от первого пункта про недетерминированный результат. Там проблема была в том, что сам ожидаемый результат плавает. Здесь результат как раз может быть вполне определённым. Проблема в другом: путь к этой проверке слишком нестабилен и слишком чувствителен к техническим деталям реализации.

Именно поэтому такие сценарии опасны. На бумаге они выглядят автоматизируемыми. Но на практике команда быстро получает не рабочий инструмент, а постоянный источник флаков и сопровождения. Тест не ловит регрессии надёжно. Он просто реагирует на любой шум в интерфейсе, рендеринге или таймингах.

Важно, что canvas — это только один из примеров. Та же проблема встречается в любом сценарии, где тесту трудно зацепиться за стабильный контракт взаимодействия. Это могут быть сложные drag-and-drop механики, нестабильные анимации, сильно динамические интерфейсы, кастомные графические редакторы, карты, диаграммы, дашборды реального времени и другие интерфейсы, где поведение пользователя воспроизводимо, а вот надёжная автоматизация — уже нет.

Главный вывод здесь простой: не всякая детерминированная логика хорошо автоматизируется. Иногда проблема не в самом сценарии, а в том, что его автоматизация получается слишком хрупкой. И если тест начинает жить на координатах, таймингах и визуальных совпадениях, это уже серьёзный сигнал, что стоимость поддержки быстро превысит пользу.

Как тогда быть?

На этом месте обычно возникает логичный вопрос: если часть сценариев невыгодно тащить в UI-автоматизацию или в тяжёлые E2E, что тогда делать? Оставить всё на ручное тестирование?

Не обязательно. Между «автоматизировать любой ценой» и «вообще ничего не автоматизировать» есть нормальный инженерный путь: подобрать для проверки правильный уровень и правильную форму автоматизации.

Первое, что стоит сделать, — перестать воспринимать E2E как универсальный ответ на любой сценарий. Если проверка плохо живёт на верхнем уровне, это не значит, что её нельзя автоматизировать вообще. Чаще всего это значит, что её нужно опустить ниже.

Часть логики разумно отдавать разработке на уровень unit-тестов. Особенно если речь идёт о бизнес-правилах, расчётах, трансформациях данных, выборе дат, статусных переходах и других вещах, которые надёжнее, дешевле и быстрее проверяются внутри кода, чем через внешний пользовательский сценарий.

Следующий уровень — компонентные, модульные и контрактные проверки. Вместо одного большого E2E-монстра часто выгоднее покрыть отдельные части процесса по отдельности. Не тянуть весь флоу целиком через UI, а декомпозировать его на несколько проверок с понятной зоной ответственности. Это даёт более быструю обратную связь, упрощает отладку и снижает стоимость сопровождения.

Очень многое вообще лучше проверять через API или CLI. Там меньше нестабильности, меньше шума от браузера и интерфейса, меньше проблем с рендерингом, а сами проверки быстрее и надёжнее. UI в таком подходе остаётся там, где ему и место: для коротких пользовательских happy-path сценариев, проверки базовой навигации, отображения ключевых состояний и критичных действий.

Ещё один рабочий путь — изоляция. Вместо того чтобы строить тяжёлый тест через живое окружение со всеми внешними зависимостями, можно поднимать локально нужный сервисный срез, базу, брокер сообщений, моки внешних систем и проверять сценарий в контролируемой среде. Такой подход требует архитектурной дисциплины, но почти всегда выигрывает у попытки автоматизировать всё через нестабильный интеграционный слой.

И только если вы уже попробовали разложить сценарий по уровням, упростить его, изолировать зависимости, перенести часть проверок ниже и всё равно не нашли способа сделать тест надёжным и экономически оправданным, тогда ручная проверка — это абсолютно нормальное решение. Не компромисс и не поражение, а трезвый инженерный выбор.

Поэтому главное правило здесь очень простое: лучше зелёный, короткий и изолированный тест, чем «правильный» интеграционный или E2E-монстр, который большую часть времени красный.

Заключение

Главная мысль простая: автоматизация — это инвестиция, а не самоцель. Если тест получается нестабильным, дорогим и сложным в сопровождении, то он не приносит пользы бизнесу, даже если формально покрывает важный сценарий. Хорошая автоматизация не та, которой много, а та, которая окупается.