Перейти к содержанию
Публикация AiManual

Как ИИ-агент провёл аудит 2600 автотестов перед миграцией с Java на .NET: кейс TravelLine

Ручной QA из TravelLine настроил ИИ-агента в OpenCode и за две недели разобрал 2600 автотестов из базы в 6500 E2E-тестов перед миграцией с Java на .NET. В разбо

Коротко

Что будет в материале

  1. 01

    Суть кейса: что сделали и зачем

  2. 02

    Подготовка: репозитории, OpenCode и выбор модели

  3. 03

    Системный промпт и контракт ответа: как сделать агента предсказуемым

  4. 04

    Интеграция с TestIT через MCP-сервер вместо прямых запросов к API

Ручной QA Ильсур Мингазов из TravelLine подключил ИИ-агента в OpenCode, чтобы разобрать накопленную базу автотестов перед миграцией с Java на .NET. За две недели агент провёл аудит примерно 2600 тестов, а статистика собрана по всей базе из 6500 E2E-тестов, которая копилась больше 15 лет. Разбор кейса опубликован на Хабре.

Агент работал с локальными копиями репозитория продукта и проекта автотестов, а к TestIT обращался через MCP-сервер. Каждый тест он относил к одной из трёх категорий: «переносить», «спустить на уровень integration/API», «не переносить». Во второй итерации к этому добавились fail rate и P85 длительности успешных прогонов, чтобы понять, какие проблемные сценарии чинить первыми.

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

Суть кейса: что сделали и зачем

Почему нельзя было просто перенести все тесты

За 15 с лишним лет у продукта TravelLine накопилось порядка 6500 E2E-тестов. Перенос «как есть» означал бы перетащить в .NET и дубли, и неактуальные проверки, и сценарии, которым место не на уровне сквозного UI-прогона. Перед миграцией команда хотела понять, что стоит переносить, что нужно чинить, что лучше спустить на уровень integration/API, а что можно признать дублем или удалить.

Причины перехода с Java на .NET в исходном материале подробно не раскрываются, поэтому здесь их не разбираем: для логики аудита это не главное. Главное - объём. Ручной разбор нескольких тысяч тестов означает недели монотонной работы: открыть тест, найти связанный код, вспомнить историю падений, принять решение и записать его так, чтобы коллега потом понял обоснование.

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

Кто и на чём это делал: роль, среда, модель

Аудит вёл ручной QA Ильсур Мингазов из TravelLine, он же инициировал подключение ИИ-агента. Технический стек кейса выглядит так:

  • среда запуска агента - OpenCode;
  • модель - GPT-5.5;
  • источник сущностей, метаданных и прогонов - TestIT, доступ через MCP-сервер;
  • локальные данные - склонированные репозиторий продукта и проект с автотестами.

Роль «ручной QA» здесь важна. Человек без глубокого бэкграунда в разработке автотестов выступал постановщиком задачи и приёмщиком результата, а не писал код аудита. Это снижает порог входа в похожий сценарий для команд, где нет отдельного инженера под внутренние инструменты. Про то, как контекстная инфраструктура вокруг агента оказывается ценнее самого агента, подробно разобрано в материале про побочный продукт ИИ-агента.

Подготовка: репозитории, OpenCode и выбор модели

Подготовка свелась к трём вещам: данные, среда и модель. На локальную машину склонировали репозиторий продукта и проект с автотестами, после чего OpenCode самостоятельно изучал структуру локальных папок. Отдельно вручную размечать тысячи файлов не пришлось.

Доступ к коду продукта - принципиальный момент. Без него агент судит о тесте по названию и шагам, а название врёт регулярно: тест «проверка бронирования» может на деле проверять отображение кнопки. С кодом продукта агент сопоставляет проверку с реальной логикой и архитектурой и может сказать, покрыт ли сценарий на другом уровне.

Почему отказались от Flash-моделей

От лёгких Flash-версий отказались сразу: на задачах сопоставления архитектуры и сложной логики они часто теряли детали. В итоге остановились на GPT-5.5. По описанию автора кейса, модель удерживала длинный системный промпт, точно вызывала MCP-инструменты и не выдумывала связи между тестами и кодом там, где их нет.

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

Обратная сторона выбора тоже есть: тяжёлая модель дороже на десятках тысяч запросов, и бюджет стоит посчитать до старта. В кейсе расчёт окупился объёмом: 2600 разобранных тестов за две недели.

Системный промпт и контракт ответа: как сделать агента предсказуемым

В системном промпте команда чётко зафиксировала правила анализа, включая критерии деления тестов на E2E и integration/API, и задала контракт ответа. Без явных правил агент на тысячах однотипных запросов начинает отвечать по-разному: одну и ту же проверку в одном прогоне запишет в E2E, в другом - в API.

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

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

Рабочий минимум для такого контракта, если собирать его с нуля:

  • категория решения: переносить, спустить на уровень integration/API, не переносить;
  • обоснование в одном-трёх предложениях со ссылкой на конкретное место в коде продукта;
  • признак дубля и ссылка на тест, который этот сценарий уже покрывает;
  • метрики прогонов, если они доступны на момент анализа;
  • флаг «нужна ручная проверка» для спорных случаев.

Правила должны быть проверяемыми. Формулировка «проанализируй тест хорошо» даёт размытый результат, который невозможно ни оспорить, ни агрегировать. Формулировка «если тест проверяет только контракт ответа API и не проверяет UI, отнеси его к integration/API» проверяема: к ней можно вернуться и посмотреть, где агент её нарушил.

Интеграция с TestIT через MCP-сервер вместо прямых запросов к API

На первой итерации команда пробовала прямые запросы к API, затем перевела взаимодействие на MCP-сервер (Model Context Protocol). Схема стала двухступенчатой: агент вызывал готовые инструменты MCP, а сервер под капотом ходил в API TestIT. Автор кейса описывает этот переход как замену самодельных вызовов на предсказуемый набор операций.

Для тех, кто не сталкивался с протоколом: MCP - способ отдать агенту набор готовых инструментов с описанными параметрами. Модель не сочиняет HTTP-запрос, она выбирает инструмент и передаёт аргументы. Всё, что связано с авторизацией, пагинацией и форматом ответа, остаётся на стороне сервера.

Что даёт MCP на практике

Сравнение двух подходов по опыту кейса:

  • прямые запросы к API дают больше свободы, но агенту приходится самому формировать вызовы, а значит ошибаться в путях, параметрах и структуре ответа;
  • MCP-сервер ограничивает набор операций, зато поведение становится предсказуемым, а инструменты переиспользуются в других задачах.

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

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

Как агент классифицировал тесты: «переносить», «спустить на уровень integration/API», «не переносить»

Три категории и их смысл в этом кейсе:

  • переносить: тесты, которые проверяют то, что действительно требует сквозного E2E и остаётся ценным после миграции;
  • спустить на уровень integration/API: сценарии, где прохождение через UI избыточно, а проверку логичнее и дешевле делать на уровне API;
  • не переносить: дубли и неактуальные проверки, которые не несут ценности в новой кодовой базе.

Критерии деления E2E и integration/API зафиксированы в системном промпте. Агент сопоставлял тест с кодом продукта и архитектурой, а не только с названием, поэтому решение опиралось на то, что тест реально проверяет. Точные формулировки критериев из источника недоступны: текст промпта в доступном фрагменте обрывается, додумывать их не стоит.

Почему часть тестов логичнее держать на уровне API

E2E-тест дороже в поддержке: он проходит через UI, зависит от вёрстки, ждёт загрузки страниц и падает от причин, не связанных с бизнес-логикой. Если сценарий проверяет расчёт, валидацию или контракт ответа, его место - integration/API. Такой тест быстрее, стабильнее и точнее указывает на место поломки.

В кейсе это вылилось в отдельные задачи на integration-тесты для разработчиков. Формулировка «спустить на уровень API» без исполнителя осталась бы красивым словом в отчёте, поэтому передача задач в разработку - обязательная часть процесса, а не необязательное приложение к нему.

Вторая итерация: fail rate и P85 для приоритизации

Классификации недостаточно: из тысяч тестов нужно выбрать, что чинить первым. Во второй итерации агент собирал до 100 последних результатов прогонов из TestIT и рассчитывал fail rate и P85 длительности успешных запусков.

МетрикаЧто показываетКак использовать
Fail rateДоля неуспешных прогонов среди последних запусковВысокий fail rate указывает на нестабильный тест или реальный дефект: такой сценарий разбирают первым
P85 длительности успешных запусков85-й перцентиль времени успешных прогоновПоказывает типичный долгий прогон без влияния единичных выбросов; кандидат на переписывание или спуск на уровень API

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

Вместе метрики дают матрицу приоритетов: часто падающие и долгие тесты разбирают первыми, стабильные и быстрые переносят без переделки, а стабильные, но медленные спускают на уровень API. Оговорка: детали второй итерации в доступном фрагменте источника раскрыты не полностью, поэтому конкретные пороги отсечения и формат выгрузки здесь не приводятся.

Показательные примеры: секции Transfers и reports

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

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

Шаблон разбора секции, который удобно повторять:

  • список тестов секции с идентификаторами;
  • категория решения по каждому тесту;
  • обоснование со ссылкой на код продукта или на тест-дубль;
  • метрики прогонов: fail rate и P85 длительности;
  • итоговое действие: перенести, передать разработчикам, удалить.

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

Результаты: что удалили, что перенесли, что отдали разработчикам

Итог двух недель: аудит примерно 2600 тестов, статистика собрана по базе из 6500 E2E-тестов. Часть тестов признали дублями и удалили. Около 450 тестов в скриншотном тестировании оказались неактуальными. По сценариям, которым место на уровне API, появились задачи на integration-тесты для разработчиков. Цифры и ход аудита приведены в первоисточнике.

Что это даёт перед миграцией по существу:

  • меньше базы для переноса, и каждый оставшийся тест имеет записанное обоснование;
  • меньше поддержки в новой кодовой базе за счёт удалённых дублей и неактуальных проверок;
  • проверки распределены по уровням: сквозные сценарии в E2E, логика в integration/API;
  • дефекты в проблемных тестах не тонут в общем списке, поскольку они получают приоритет по метрикам.

Читать эти цифры как «сократили 2600 тестов» неверно. Аудит разобрал 2600 тестов, а удаление и перевод на другой уровень касаются конкретных групп, названных выше: дублей, скриншотных проверок и сценариев, ушедших в integration.

Ограничения подхода и что стоит учесть перед повторением

Опыт одной команды легко переоценить. Прямые ограничения кейса:

  • внутренние названия и идентификаторы в источнике обезличены, объёмы округлены;
  • причины перехода с Java на .NET не раскрываются, поэтому нельзя утверждать, что подход сработает так же при другом типе миграции;
  • полный текст системного промпта и контракта ответа в доступном фрагменте обрывается;
  • детали второй итерации и разбивка по секциям Transfers и reports раскрыты не полностью.

Риски, которые стоит заложить в план:

  • модель может уверенно связать тест с чужим участком кода, поэтому выборочная ручная проверка выводов обязательна;
  • стоимость тяжёлой модели растёт линейно с объёмом базы, а бюджет считают до старта;
  • качество аудита зависит от метаданных в TestIT: если история прогонов обрывочна, fail rate и P85 дадут искажённую картину;
  • лёгкие Flash-модели на этой задаче теряли детали, поэтому экономия на модели может стоить качества всего аудита;
  • решение об удалении теста остаётся за человеком: агент готовит обоснование, а не приговор.

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

Стоит ли повторять: чек-лист для вашей команды

Условия, при которых подход похож на оправданный:

  1. Накоплена большая база E2E-тестов, которую руками не разобрать за разумное время.
  2. Впереди миграция, смена фреймворка или крупный рефакторинг, то есть решения по каждому тесту всё равно нужно принять.
  3. Есть система управления тестированием с историей прогонов: TestIT или аналог, откуда можно достать статусы и длительности.
  4. Есть доступ к репозиториям продукта и автотестов, и его можно дать агенту локально.
  5. Команда готова поддерживать MCP-сервер или другой слой инструментов над API тест-менеджмента.
  6. Есть бюджет на тяжёлую модель и человек, который выборочно проверяет выводы.

Стартовые шаги выглядят так: зафиксировать критерии классификации в системном промпте, задать контракт ответа с полями для обоснования и метрик, прогнать агента на одной секции вроде Transfers или reports, перечитать выборку руками и только после этого масштабировать на всю базу. Опыт с виртуальными исполнителями в трекере показывает ту же закономерность: чем строже описаны доступы и правила, тем меньше сюрпризов на выходе, о чём подробно в разборе про агентов в Jira.

Гарантий по срокам и экономии давать нельзя: результат зависит от состояния базы, качества метаданных и готовности команды разбирать спорные классификации. Ориентир из кейса - две недели на 2600 тестов при базе 6500, с полной моделью вместо лёгкой и с отдельным слоем интеграции к TestIT.

Подписаться на канал