Я в тестировании много лет. И чем дальше, тем отчетливее понимаю: наибольшая проблема не в том, чтобы найти баг, а в том, чтобы поддерживать сценарии тестирования в актуальном состоянии. Начинал я с ручных сценариев в TMS. Потом были Selenium, Cypress, Playwright. Казалось, автоматизация решит проблему. Но она ее просто перекладывает. Вместо того, чтобы щелкать кейсы руками, ты пишешь код, чинишь селекторы и разбираешься, почему тест, который вчера проходил, сегодня мистическим образом падает. А на фоне вечное «надо катить в прод прямо сейчас, в идеале вчера».
Тесты всегда оказываются в конце списка приоритетов: их пишут в спешке, а поддерживают по остаточному принципу, еще ладно бы свои. Обиднее, когда достаются унаследованные со времен царя Гороха, написанные другими людьми и под другую архитектуру. За годы я писал и поддерживал, наверное, тысячи тестов — ручных и автоматизированных. И все это время меня не покидало ощущение, что процесс можно сделать легче.
В общем, устав от постоянной гонки за качеством продукта при постоянном отсутствии времени, я задумался о поиске супер-пупер-тулы, которая будет писать тесты сама (в идеале, чтобы и сама запускала). Разумеется, с ростом популярности нейросетей возник вопрос: «А что, если всю работу целиком от сценария до тестирования будет выполнять машина?». Воспользовавшись тем, что такого решения еще нет, мы с моим коллегой @JSK решили: а давайте его изобретем? Спойлер: дело закончилось патентом.

Не поймите меня неправильно: работу я люблю. В тех местах, где есть хоть какой-то простор для творчества или поле для исследований. А тут… В жизни тебе нужно две минуты, чтобы прокликать все значимые элементы на странице. Но чтобы написать бумажку обо всех вариантах того, как нужно кликать, запустить и перепроверить автотест, нужно намного больше, потому что между «сделать» и «описать, как сделать» лежит пропасть. И чем больше проект, тем эта пропасть шире.
Сначала ты пишешь тест-кейс. Потом его нужно оформить в TMS: шаги, ожидаемый результат, предустановки, тестовые данные, связи с требованиями, метки, приоритеты. Потом поддерживать в актуальном состоянии, потому что интерфейс поменялся, а кейс остался. Потом писать автотест, который делает то же самое, но на языке кода. Потом поддерживать и его, потому что селекторы сломались, API изменился, а среда внезапно поехала.
Я провел собственное исследование текущих инструментов, автоматизирующих ту или иную часть работы инженера тестирования. Существующие продукты сокращают время написания тестов, но все еще требуют много усилий. Например, Selenium IDE дает возможность записать свои действия и воспроизводить их потом как автоматический тест. Но хотелось бы, чтобы и генерация осмысленных сценариев была полностью переложена с наших плеч на машинные.
Причем здесь машинный перевод
Главная головная боль автотестирования — это разрыв между тем, что нужно проверить, и тем, как это выразить в коде. Тестировщик думает на языке пользователя: «открыть форму, заполнить, отправить, проверить». Пользователь видит кнопку, поле, ссылку и взаимодействует с ними на уровне смысла: «нажми сюда», «введи email», «убедись, что появилось сообщение». Но чтобы автоматизировать это же действие, приходится спускаться на уровень разметки: искать селектор, проверять его уникальность, думать о том, не сломается ли он при следующем рефакторинге верстки. Автотест живет на языке #login-form > input[name="email"], button[type="submit"], await page.waitForSelector(...).
Между этими двумя языками нет прямого моста, и весь труд по написанию теста как раз в том, чтобы вручную его воздвигнуть: перевести намерение в селекторы, а селекторы использовать в коде теста. Чем сложнее интерфейс, тем длиннее этот путь и тем больше рутины.
Взяв от текущих инструментов исключительно хорошее — автоматизацию процесса, — я стал искать решение проблемы. Я подумал: а почему бы не научить систему саму «понимать», куда нажимать, а куда вводить текст?
Первое, что пришло в голову, — использовать компьютерное зрение. А что? Пусть машины сами смотрят, где на странице кнопки и поля! Но эту идею довольно быстро отмели: зачем усложнять, если DOM уже содержит все нужные нам элементы, с которыми можно и нужно взаимодействовать в автоматизированных тестах? О'кей, но как научить модель читать и понимать структуру DOM?
Я прочитал несколько статей (например, вот эту), и ко мне начала закрадываться мысль: если мы можем научить нейросеть переводить текст с русского на английский, то можем и заставить ее «переводить» HTML-разметку в последовательность тестовых действий.
«Трансформеры, — решили мы. — Нам нужны трансформеры».
Генерация тест-кейса по элементу интерфейса — это задача, изоморфная машинному переводу. На поверхности все кажется очень просто:
на входе: исходный код (HTML);
на выходе: целевой код (тест-скрипт на Java, Python, JavaScript).
Это и стало главной идеей нашего изобретения.
Лирическое отступление: почему вообще трансформеры
Все дело в механизме внимания (Attention), который идеально подходил под наши задачи. Точно так же, как в естественных языках трансформеры вычленяют наиболее важные слова и понимают суть сказанного, они могут научиться определять, какие части формальных языков, например HTML-кода, наиболее значимы для формирования теста. Кодировщик (Encoder) «понимает» структуру страницы, а декодировщик (Decoder) «генерирует» на ее основе последовательность команд для тестового фреймворка.

Важное уточнение: здесь аналогия с машинным переводом работает не идеально. В естественном языке смысл предложения сохраняется при переводе, потому что оба языка описывают одну и ту же реальность. В случае HTML → тест-скрипт модель должна не «перевести» разметку, а вывести из нее намерение: какие элементы интерактивны, какие сценарии с ними возможны, какие проверки имеют смысл. Это ближе к задаче извлечения структуры, чем к переводу, но как метафора работает.
Мы дообучали существующие модели, точнее одну, на которой мы проводили эксперименты, адаптируя ее под нашу специфическую задачу — «перевод» на язык тестов. Для этого в контексте мы использовали сет кейсов нашего живого проекта, на котором уже были написаны тесты. В конечной реализации мы хотели сделать стандарт для всех QA-инженеров и дообучать модель на базе тестов, написанных всеми ребятами с разных проектов. Тут мы планировали сформировать RAG как базу знаний, основанную на существующих тестах. Но... ниже расскажу, как получилось по факту.
Внутри автотестировщика
Для того, чтобы наши грандиозные теоретические планы воплотились в рабочую E2E-систему автотестирования, нужно было пройти через две фазы: обучение и генерацию. Давайте погрузимся в особенности анатомии процесса.
1. Фаза обучения: создаем «разговорник» для тестов
Самое сложное на этапе обучения — это создать качественный датасет для тренировки модели. Мы не можем просто скормить LLM-ке HTML рандомных сайтов: на них порой слишком мало элементов взаимодействия в разных вариациях. Да и нет смысла тестировать на чем попало: хотелось бы приносить пользу именно проекту, на котором я работаю. Короче, нам нужен был датасет, состоящий из пар «HTML-элемент → корректный тест-кейс». Угадайте, как мы это решили?
Синтетическая генерация данных
Сначала я рванул писать генератор на Python: был уверен, что это лучшая идея. Генератор должен был производить тысячи сайтов с вариациями типовых элементов интерфейса: форм авторизации, кнопок, полей ввода. Я даже написал его, но… Спасибо коллеге, который вовремя задал сакраментальный вопрос: «Зачем?» — и я пошел писать промпт для модели. Сказано — сделано:
Сгенерируй HTML-страницы для обучения ИИ-модели тестирования (автотесты). Требования к странице: Тематика: [Укажи тему, например: форма регистрации / корзина интернет-магазина / личный кабинет]. Элементы: добавь минимум 5 разных элементов управления (input разных типов, select, checkbox, textarea, button, ссылки). Вариативность: используй разные подходы к вёрстке (где-то связывай <label> через атрибут for, где-то вкладывай input внутрь label, используй понятные id, name и placeholders). Оформление: напиши чистый, валидный HTML5-код. Весь CSS (стили) и простой JS (валидация формы) добавь прямо внутрь файла в теги <style> и <script>. Выведи ТОЛЬКО готовый HTML-код без лишнего текста и объяснений.
Ответ модели:
«Если вы планируете генерировать такие страницы пачками (датасетом), я могу написать Python-скрипт, который автоматически соберет сотни уникальных комбинаций HTML-форм с помощью библиотек генерации данных. Нужен такой скрипт?»
Признаю: на момент разработки этого концепта промпт был не идеален, но с поставленной задачей справился.
Нормализация
Итак, датасет у нас есть, мы знаем, какие в нем элементы, соответственно, представляемый ожидаемый результат. Теперь с ним можно работать. Для начала все данные очищаются от шума (декоративные div, неиспользуемые классы) и приводятся к нижнему регистру. Цель — научить модель видеть суть, а не случайные атрибуты.
Для каждого сгенерированного элемента автоматически пишется эталонный тест-кейс. Здесь мне снова вспомнилась фраза руководителя, так что промпт родился сам собой:
Изучи предоставленный HTML-код страницы и сгенерируй для него эталонные тестовые сценарии (тест-кейсы). Выходной формат: [Укажи нужный формат, например: Gherkin (Given-When-Then) / Код Python + Playwright / Чек-лист на русском]. Правила генерации: Покрытие: создай сценарии для ВСЕХ найденных интерактивных элементов (кнопок, полей ввода, чекбоксов, выпадающих списков, ссылок). Локаторы: в сценариях используй точные и надёжные селекторы из HTML (id, name, data-testid, aria-label или уникальный текст). Тест-кейсы: напиши как позитивные сценарии (успешное заполнение и отправка), так и негативные (валидация пустых полей, некорректный ввод, если в HTML есть признаки валидации). Изоляция: каждый сценарий должен быть независимым и проверять конкретную пользовательскую историю. Выведи только готовые тестовые сценарии без вводных слов и пояснений.
Сложность теперь сводилась только к ревью полученных результатов. Это позволило быстро создать большую обучающую выборку. Тут я должен бы показать часть этого кода, но… еще немного терпения, дальше поймете, почему его здесь нет.
2. Фаза генерации: магия на практике
Когда модель обучена, процесс выглядит для пользователя до смешного просто:
парсинг: система загружает целевой URL и парсит его HTML;
предобработка: данные очищаются и нормализуются;
инференс модели: наша Transformer-модель «переводит» полученный HTML в код тестов;
вывод: пользователь получает готовые тест-кейсы и сценарии в нужном формате.
Пример из жизни:
html <!DOCTYPE html> <html> <body> <!-- Информационная вкладка с data-атрибутом для локатора --> <div data-tab="information">Information</div> <!-- Поле ID сервера с явным идентификатором --> <div id="id_field">srv-9876-abc</div> </body> </html> python @pytest.mark.smoke @pytest.mark.tabs class TestSiteTabsSmoke: """Smoke tests for tabs functionality.""" def test_successful_tab_navigation(self, authorized_page: Page) -> None: """ Test successful navigation through all server tabs. Scenario: Успешная навигация по вкладкам сайта Priority: High """ tabs_page = TabsPage(authorized_page) site_info_page = SiteInfoPage(authorized_page) with allure.step("Verify Information tab is visible") if HAS_ALLURE else tabs_page: expect(tabs_page.list_base_item_information_tab).to_be_visible(timeout=10000) with allure.step("Click Information tab and verify content") if HAS_ALLURE else tabs_page: tabs_page.click_list_base_item_information_tab() authorized_page.wait_for_load_state("networkidle") expect(site_info_page.id_field).to_be_visible(timeout=10000)
Важно отметить: для навигации по сайту мы обычно используем XPath. Для тех, кто не в теме: это такой путеводитель, который описывает нейронке дорогу до нужного элемента в интерфейсе, чтобы она его оттестировала. Да, LLM умеют генерировать и их, НО поскольку это прежде всего языковые модели, делают они это из рук вон плохо и знатно фантазируют. Точнее так: модель может выдать синтаксически валидный XPath, который не соответствует реальному дереву DOM, потому что путь зависит от конкретной структуры страницы, а не от семантики элемента. На стадии ревью мы часто получали несуществующие XPath. Чтобы укротить слишком живое воображение машин, мы написали MCP, который решал две основные проблемы с XPath:
проверка существования пути, факт того, что элемент по XPath действительно доступен в DOM;
сокращение размера XPath, поскольку сгенерированные варианты очень большие и попросту быстро забивали контекст.
Собрав все вместе, мы получили агента и выстроили с ним следующий процесс:
Мы формируем HTML интересующей нас страницы.
Передаем его для поиска элементов, с которыми можно взаимодействовать.
Получаем до них XPath.
MCP проверяет валидность сгенерированных путей.
Генерируем тесты для найденных элементов.
Запускаем тесты.
...Но пока мы все это строили, вышла GLM 5.3 — и она сама умела писать тесты не хуже нас из коробки. Поэтому я и не привел выше код, который писала наша модель, потому что дальше мы ехали уже на GLM и с ветерком. Пайплайн при этом не пропал: он превратился в обвязку вокруг модели — нормализация, MCP для XPath, проверка валидности, ревью. То есть мы перестали дообучать свою модель, но сохранили все, что делало процесс управляемым и предсказуемым. Также стали думать над тем, чтобы не передавать код страницы модели, а создать агента, который сам будет по URL ходить на нужную страницу и забирать код. На момент написания статьи мы продолжаем дорабатывать агента, сейчас это делать легче, поскольку новые модели очень помогают.
По результатам работы нам удалось оформить патент на данный подход, поскольку на момент исследования не нашлось ни одной системы с такой степенью автоматизации процесса.
Получение патента, конечно, изначально не было целью: цель была разгрузить инженера тестирования путем автоматизации рутинных задач. На выходе мы получили:
Скорость. Генерация сотни тест-кейсов из сложного интерфейса занимает минуты, а не недели.
Покрытие. Модель может находить нетривиальные сценарии, которые человек мог бы упустить.
Адаптивность. Система может дообучаться на ваших собственных, уже написанных тестах, становясь точнее и «ближе» к вашему проекту.
Раннее тестирование. Тесты можно генерировать сразу после верстки, не дожидаясь готовности бэкенда.
Это, конечно, не панацея от всех проблем, и идеальная точность пока не достигнута, но меня радует сам факт, что с таким подходом труд человека-тестировщика — это уже не монотонная рутина по штамповке тест-кейсов, а творческая работа по контролю качества. В то же время сам инженер не остается за бортом производственного процесса: он все еще нужен для ревью и тонкой настройки сгенерированных сценариев.
Вместо заключения
Путь от идеи до работающего прототипа и получения патента был невероятно сложным, но безумно интересным. Мы смогли соединить две, казалось бы, не связанные области: лингвистические модели с инженерией качества ПО — но это сработало! Вы, конечно, можете сказать, что сейчас модели могут все делать сами и ничего тут нового нет, но главная мысль, которую мне хотелось бы донести этим прецедентом: сейчас развитие технологий ИИ идет такими быстрыми темпами, что разработка и защита гипотез человеком (даже если он не один) за этим не поспевает, и нам нужно разумно использовать имеющиеся ресурсы, чтобы делегировать когнитивную нагрузку.
Будущее очевидно за гибридными системами, где машина берет на себя рутину и генерацию идей, а человек — стратегию, анализ, критическое мышление и сложные кейсы. Наше решение — пока скромный шаг в этом направлении. Посмотрим, куда заведет эта тропа.
Сегодня наш агент может сам ходить на вверенные ему страницы, получать информацию о разметке, генерировать код и проводить ревью — правда, пока не идеально.
Рассказывайте, видите ли вы применение таким подходам в своих проектах? И стали бы вы доверять ИИ написание тестов для вашего кода?

