Как проверить, что ИИ-агент в 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-автотестов эффективно находит ошибки. Если критичная функция ещё не покрыта — мы дописываем тесты. В следующий раз проблему обнаружим быстрее.