В этой статье расскажу о практическом применении больших языковых моделей (LLM) в сочетании с традиционными инструментами автоматизации Python/Selenium для повышения надежности тестов.
Статья состоит из следующих разделов:
1. Что такое self-healing тесты
2. Hardware конфигурация
3. Software конфигурация
4. Испытываем API локальной LLM
5. Встраиваем в тесты
6. Ограничения
7. Перспективы
Что такое self-healing тесты
Автоматические тесты должны быть надежными, чтобы не допускать ложных срабатываний. Такие тесты повышают доверие к их результатам и позволяют глубже внедрять автотестирование в процессы. Повысить надёжность автоматических тестов можно за счёт решения основных проблем, которые встречаются во время их эксплуатации. Все эти проблемы приводят к ложным срабатываниям:
1. Меняющиеся свойства элементов тестироуемого приложения.
2. Ненадёжная инфраструктура.
3. Чрезмерная скорость работы инструмента автоматизации.
Исходя из встречаемых проблем будем понимать, что self-healing (самоисправляющиеся) тесты – это те, что могут автоматически адаптировать своё поведение в момент возникновения проблемы. Акцент текущей реализации сделан на решении проблемы 1.
Hardware конфигурация
В таблице ниже приведены измерения 2х параметров работы модели на наших конфигурациях и описание самих конфигураций.
1. MacMini 2023: Результаты работы модели: |
2. MacBook Pro 2023: Результаты работы модели: |
TTFT – time to first token (время, спустя которое пользователь начнёт получать ответ) |
В силу ограниченного количества железа и опытной эксплуатации, используем только 1 сервер в первой конфигурации.
Software конфигурация
1. LMStudio https://lmstudio.ai/ – ”IDE” – удобно для отладки промптов, конфигурации параметров модели, оффлайн запуска и поднятия ”сервера моделей”



2. Модель lmstudio-community/Qwen2.5-7B-Instruct-MLX-4bit с HuggingFace (удобно скачать через LMStudio).
3. openai pip пакет.
Испытываем API локальной LLM
(venv) user@MacBook-Pro-Admin-2 web2 % cat tttt
from openai import OpenAI
LLM_URL = 'http://<IP_OF_SERVER_IN_YOUR_NETWORK>:1234/v1'
LLM_MODEL = 'qwen2.5-7b-instruct-mlx'
def call_llm(request):
client = OpenAI(base_url=LLM_URL, api_key="lm-studio")
completion = client.chat.completions.create(
model=LLM_MODEL,
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": request,
},
],
},
],
)
return completion.choices[0].message.content
print(call_llm('Да или нет?'))
(venv) user@MacBook-Pro-Admin-2 web2 %
(venv) user@MacBook-Pro-Admin-2 web2 % python tttt
Вы задали вопрос, но не указали, что именно нужно ответить "да" или "нет" на. Пожалуйста, уточните свой вопрос, чтобы я мог помочь вам.
Встраиваем в тесты
Вся логика начинается с метода get_object, который через базовый PageObject доступен конечным PageObject’ам.

Благодаря RLS (Run-time Locators Storage), все последующие тесты внутри тестового прогона не будут фейлиться на проблемном элементе. Важным также является организация design-time хранилища локаторов. Это отдельные классы, подключаемые к функциональным PageObject’ам. Выглядят примерно так:
class LLogin:
@staticmethod
def L_I18N_TEXTFIELD_LOGIN(lang=''):
"""поле ввода логина"""
return ('xpath', f'//*[@e2e-id="I intentionally broke this locator"]')
Благодаря соглашению об именовании локаторов (имя начинается с префикса L_) и о работе с объектами страниц (обращения к ним делаются только через Page.get_object(L_I18N_TEXTFIELD_LOGIN)) можем по стеку вытащить имя локатора и сохранить его в Run-time Locators Storage.
Благодаря докстрингу метода локатора (“””поле ввода пароля”””) имеем элегантное решение где хранить человеческое описание локатора, которое и используется для инференса LLM.

Пока не делаем автоподмены старых локаторов на новые – сгенерированные LLM. Показываем их в allure-репорте.

Ограничения
-
Одновременное обращение в LLM за инференсом увеличивает TTFT для последующих запросов. Например, если сделать сразу 3 запроса на нашей первой конфигурации (TTFT=35), то ответ по первому получим через 35 секунд (ОК), по второму – через ~70 секунд и через ~105 секунд по третьему. Похоже на очередь.
-
Если решить использовать такой подход с конфигурацией, дающей долгий TTFT, для многих тестов/когда почти все локаторы отваливаются – всё встанет в очередь и ваш аналог Gitlab прекратит выполнения пайплайна с тестами по таймауту
-
В условиях ограниченных HW-ресурсов нельзя просто взять и подключить все локаторы к LLM – потенциально возникнет очередь из-за многопоточного запуска тестов, даже если ваш продукт стабилен и разработчики выделяют специальные свойства для автотестов (как e2e-id в нашем случае). Для минимизации этой проблемы есть простая стратегия: автоматически считаем сколько раз используется каждый локатор в тест ране и подключаем только самые часто используемые. Например, когда почти все ваши тесты начинаются со страницы авторизации, вы получите максимальное число использований локаторов для полей ввода логина, пароля и кнопки Войти. Подключив их вы предостережёте себя от провала всех тестов в самом начале.
-
Размер контекста – количество токенов в промпте. Чем больше размер – тем больше потребление памяти. Чем меньше размер – тем сильнее вам придётся ухищряться чтобы дать LLM модели подходящую часть HTML для inference. В нашем случае делаем предобработку – из всего page_source, отдаваемого Selenium’ом, вырезаем лишнее – теги <style></style> и <script></script> вместе с содержимым. Скорее всего будем урезать еще для страниц с большим количество элементов. Размер нашего контекста – 10000 токенов. Согласно документации qwen – 1 токен это в среднем 3-4 символа английского текста.
Перспективы
-
Продукты, находящиеся в относительно активной разработке, теперь всё-таки могут иметь UI-автотесты благодаря self-healing подходу.
-
Автотестирование относительно устоявшихся продуктов станет более надёжным за счет адаптируемости к изменениям в приложении.
-
Автоматическое тестирование относительно устоявшихся продуктов может покрыть больше сценариев (например, в тестировании desktop платформ, где иногда требуется доступ к системным окнам) за счёт внедрения мультимодальных LLM либо комбинации нескольких простых моделей.
Автор: breakingtesting