Как мы написали UI-тесты для ИИ-агента внутри JetBrains IDE

Как мы написали UI-тесты для ИИ-агента внутри JetBrains IDE

Как проверить, что ИИ-агент в IDE работает, если на одинаковые запросы LLM отвечает по-разному? Ответы модели недетерминированы, а интерфейс и бизнес-логика — вполне детерминированы. Их нужно тестировать отдельно.

Мы разрабатываем ИИ-агента, встраиваемого в JetBrains IDE. В этой статье — о том, как мы построили UI-автоматизацию плагина, чтобы тесты ловили регрессии в интерфейсе и логике, но не падали из-за нестабильности LLM.

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

Подход к автоматизации

Veai — это ИИ-агент, встраиваемый в JetBrains IDE. Он помогает писать код, отлаживать и тестировать приложения.

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

В проекте уже были тесты на разных уровнях: на уровне модели IDE, для LLM-провайдеров, агентский бенчмарк. Но UI-тестов не было — хотя наш продукт имеет графический интерфейс, в отличие от консольных ИИ-агентов.

Тестирование приложений с LLM можно условно разделить на две части:

  • классические функции — например, хранение настроек пользователя;
  • ИИ-функции — например, получение ответа от LLM.

Отправляя агенту запрос, можно получить ответ в чате или в терминале IDE. Это создаёт риски нестабильности UI-тестов. Мы решили проблему, разделив тесты на несколько уровней.

В Full-прогоне мы не мокируем LLM, а работаем с реальным сервером. Это позволяет проверять полную цепочку: IDE-плагин, сервер лицензий, LLM-сервер, внутренние библиотеки и другие компоненты. Если один из них недоступен — мы узнаем об этом быстро.

При тестировании на реальном LLM-сервере мы отправляем короткий запрос: «2+2=? Ответь покороче». Цель — не получить «4», а убедиться, что:

  • ответ приходит после предусловий;
  • интерфейс его отображает;
  • стриминг токенов завершается.

Качество ИИ-сценариев оценивается отдельно — с помощью бенчмарка и подхода LLM-as-a-Judge. Эту тему мы оставим за рамками статьи.

Техническое решение

Starter и Driver

Для автоматизации тестирования плагинов JetBrains IDE мы используем библиотеки Starter и Driver.

  • Starter — подготавливает IDE, настраивает тестовый проект, собирает результаты.
  • Driver — взаимодействует с интерфейсом и получает доступ к внутреннему состоянию IDE через прокси.

Решение поддерживает паттерн Page Object. Несмотря на то что это десктопное приложение, элементы интерфейса можно описывать и искать с помощью XPath — как в вебе.

Иногда в иерархии нет подходящих локаторов. Тогда в продуктовом коде мы добавляем accessibleContext.accessibleName, чтобы находить элементы по имени. В других случаях приходится корректировать правила обфускации, чтобы сохранить доступ к элементам по классу.

Автотесты не начинают каждый раз с Welcome-экрана. Мы подготавливаем состояние через XML-настройки плагина — это ускоряет тесты.

Driver также поддерживает JMX (Java Management Extensions). С его помощью мы создаём прокси для внутренних компонентов IDE и получаем доступ к их состоянию. Это позволяет делать более глубокие проверки.

В Driver встроена поддержка Allure. После настройки и запуска тестов появляется папка allure-results, из которой можно сгенерировать отчёт.

Вот пример Smoke-теста с использованием Page Object:

В этом сценарии используется EnterpriseKey.DUMMY. На UI появится сетевая ошибка, но тест останется стабильным. Главное — запрос не уйдёт в LLM, что исключает влияние модели на результат.

Метод assertInChatDump — наша утилита. Она использует JMX, чтобы получить внутреннее состояние IDE в виде чата ИИ-агента, и позволяет проверять данные через JSONPath.

Continuous Integration

В CI мы поддерживаем несколько конфигураций: версии IntelliJ, разные JetBrains IDE, feature flags и обфускацию.

Обфускация важна: иногда функция работает в dev-сборке, но ломается после обфускации. Это может быть связано с потоками данных, не затрагивающими UI. Чтобы выявлять такие случаи, мы запускаем тесты на обфусцированном артефакте в ночной сборке — из-за увеличения времени сборки это не подходит для частых прогонов.

IntelliJ Platform регулярно обновляется: выходят версии 2025.1, 2025.2 и другие. Также нужно поддерживать разные IDE: IDEA, PyCharm, Rider, WebStorm и т.д.

Автоматизация по нескольким IDE окупается в долгосрочной перспективе — ручное тестирование всех комбинаций слишком ресурсозатратно.

Режим запуска: headless vs non-headless. Driver работает с реальным графическим интерфейсом, включая движение курсора. При локальном запуске тест может перехватывать фокус — это мешает параллельной работе. В CI на Linux проблема решается с помощью Xvfb (X Virtual Framebuffer), который эмулирует графическую среду без монитора.

Мы также используем повторные запуски тестов через Test Retry Gradle plugin. Каждый тест перезапускается не более одного раза, а на весь прогон допускается не более трёх падений. Эти значения показали себя как устойчивый компромисс.

Результаты

Мы написали несколько десятков UI-тестов на следующие функции:

  • настройки плагина;
  • переходы между состояниями чата;
  • внутреннее состояние JSON чата (выбор агента и LLM);
  • вызов SKILL;
  • навигация по истории чатов;
  • вход нового пользователя.

Багрепорты

Примеры проблем, найденных тестами:

  • после добавления drag & drop в чате ломался copy & paste;
  • при обновлении прогресс-бара контекста не учитывались все LLM-провайдеры — это могло привести к некорректной отрисовке и несвоевременному сжатию контекста;
  • при выборе агента из чата на UI не отображались все доступные LLM-провайдеры;
  • в сценарии восстановления агента после ошибки тесты начали «моргать» — потому что сам UI стал нестабильным.

Однажды ночная сборка выявила падение тестов из-за новой конфигурации LLM-сервера. Это помогло оперативно оценить нестабильность конфигурации.

Мы убедились: даже небольшой набор UI-автотестов эффективно находит ошибки. Если критичная функция ещё не покрыта — мы дописываем тесты. В следующий раз проблему обнаружим быстрее.

Читать оригинал