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

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

Привет! На связи Саша Мищенко, тимлид платформенной команды, и Света Чекунова, Senior QA Auto. Нам кажется, что мы нашли этот баланс.

Без догм, зато с кучей собственных инструментов и подходов. Рассказываем, как у нас всё устроено, с чего мы начинали, где было больно и какие решения сработали.

Как мы выстраивали систему

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

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

Это вроде работало, но ощущалось, что вот-вот всё развалится. Регресс в этот момент существовал скорее как набор разрозненных проверок. Он был плохо описан и слабо структурирован: у команд не было единой, понятной модели того, что именно и как нужно проверять. Каждый тестировщик держал критичные сценарии у себя в голове и опирался на собственный опыт. В итоге часть зон покрывалась несколько раз, а часть вообще выпадала из проверки.

Ситуацию осложняло и то, что продукт делали несколько команд, контекст между ними был разорван. Тестировщик хорошо понимал свою часть, но почти не видел соседние. Регресс получался не системным, а скорее по памяти и на опыте.

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

Но постепенно становилось понятно: временный подход начинает упираться в ограничения. Тогда мы начали создавать систему.

1. Попытка навести порядок. Мы начали с того, что попробовали хотя бы в первом приближении описать продукт. Так появилась тестовая модель — неидеальная, но уже полезная.

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

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

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

2. Железо, метрики и игровой подход. Дальше стало понятно, что одного функционального тестирования недостаточно, поэтому начали всплывать проблемы с производительностью.

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

Отдельным направлением стала производительность. Мы начали мерить FPS, как в играх. 

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

Параллельно разработчики сделали FPS-мониторинг, который позволял следить не только за тестовыми сценариями, но и за реальной производительностью у пользователей. Это дало очень прикладное понимание, где именно продукт начинает деградировать.

3. Аккуратный релиз и работа с устройствами. По мере роста приложения мы начали смотреть не только на тесты, но и на реальную базу устройств из аналитики. Выписывали самые слабые, самые проблемные и даже неожиданные конфигурации.

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

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

Какие подходы у нас прижились

Ромб вместо пирамиды. Довольно быстро стало понятно, что классическая, пирамидальная модель тестирования в чистом виде у нас на фронтенде не работает.

Пирамида предполагает, что внизу много юнит-тестов, выше — интеграционные, а на самом верху — немного e2e.

В чём суть: мы осознанно выбрали кросс-платформу React Native, а для неё характерны проблемы с перформансом и баги на стыке рендеринга и JS runtime. В классической нативной разработке при разделении продукта на iOS и Android таких сценариев было бы заметно меньше. 

В результате большая часть багов у нас проявляется не в изолированной логике, а на границах системы «клиент ↔ API, состояние ↔ пользовательский сценарий». Эти зоны плохо покрываются юнит-тестами, даже если их очень много.

Поэтому мы сместили фокус в сторону интеграционных и e2e-тестов. И добавили слой компонентных. Получился ромб. Если упростить, то логика такая: 

  1. Юнит-тесты остаются базой, но не являются центральным слоем. 

  2. Основная защита уходит в компонентные тесты с честным рендерингом.

  3. Дальше уже идут интеграционные тесты.

  4. E2e-тесты используются немного, для длинных пользовательских сценариев.

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

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

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

Искусственный интеллект. Искусственный интеллект у нас довольно естественно встроился в процессы. 

Тест-кейсы у нас живут в системе (аналог TestRail) и исторически полностью писались вручную. Сейчас большую часть этого процесса закрывает ИИ: мы даём ему макеты или задачу, он предлагает сценарии проверок, а дальше тестировщик это дорабатывает. 

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

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

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

К чему мы идём

Если упростить, мы движемся к shift-left testing — стремимся к тому, чтобы тестирование начиналось раньше. Не после разработки и не после макетов, а уже на этапе задачи. В нашем идеальном мире это выглядит так: 

  1. В разработку приходит задача — сразу с понятными сценариями и минимальными макетами.

  2. Тестировщики в тот же момент забирают задачу — прогоняют всё через ИИ и себя, разбираются со всеми вопросами и вместе с нейросетью пишут тест-кейсы. 

Это было бы прекрасно, сэкономило бы силы и время. Постепенно идём к таким процессам. Ну и конечно, стремимся к тому, чтобы стабильные автотесты покрывали основной функционал и длинные пользовательские сценарии.

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

  • Прорабатываем тестовую модель.

  • Пробуем с ИИ формировать документацию по текущему коду, если её нет.

  • Используем промпт, с помощью которого можно уточнять, что было реализовано и как это работает.

  • Проводим общие встречи и ведём каналы, где делимся знаниями.

В целом роль тестировщика постепенно меняется. Меньше ручного описания сценариев и разборов вроде «что с чем связано», больше проверки уже готовой логики и сложных случаев. ИИ забирает на себя черновую работу — автотесты, тест-кейсы, разметку, уточнения. А человек остаётся там, где нужен контекст продукта и здравый смысл.

Комментарии (5)


  1. Kot_na_klaviature
    27.05.2026 14:20

    ИИ забирает на себя черновую работу — автотесты

    Тесты - это не черновая работа. Ничем не отличается от кода приложения. Там внезапно - тоже нужно качество кода, поддерживаемость, читаемость и архитектура. А то быстро все скатится к лапше, которую люди читать перестанут и ллм будет делать, что захочется (частенько всякие неприятные глупости).


    1. Pumppeedd Автор
      27.05.2026 14:20

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


  1. Ariless
    27.05.2026 14:20

    Согласна с предыдущим комментатором - тесты это не черновая работа. Добавлю конкретный пример: писала тест на demographic neutrality для медицинской системы, AI сгенерировал набор: “25-летний мужчина → Cardiologist”, “70-летняя женщина → Cardiologist”. Код чистый, логика понятная. Проблему нашла при ревью: “А ребёнок?” Для Pediatrician демография должна влиять на рекомендацию - это клинически корректное поведение. AI не знал этой границы, тест верифицировал неправильную вещь.

    Это не про качество кода (тут как раз всё было аккуратно). Это про то, что без понимания домена тест может быть синтаксически идеальным и семантически неверным. В моём случае это создало иллюзию покрытия там, где его не было.


    1. Kot_na_klaviature
      27.05.2026 14:20

      Да вот только что. У агента не получилось авторизовать юзера и он в метод проверки авторизации

      $page = $page

      ->fill('email', $user->email)

      ->fill('password', $password)

      ->click('@submit-button');

      test()->assertAuthenticatedAs($user);

      втихаря встроил программную авторизацию

      test()->actingAs($user);

      Т.е. подстроил тест под результат. И теперь везде будет зелень.


      1. Ariless
        27.05.2026 14:20

        Ваш пример страшнее :) тест был правильным, пока агент его не "починил".