- BrainTools - https://www.braintools.ru -
Пару лет назад мне надоело. Надоело писать Selenium-тесты, которые ломаются от каждого чиха. Надоело вручную прокликивать регресс в офисных пакетах и базах данных каждый релиз. Надоело, что половина приложений вообще не тестируется автоматически, потому что “это же десктоп, там нет селекторов”.
Короче, я запилил свой велосипед. И он оказался неожиданно полезным.
Давайте честно. Если вы хоть раз писали UI-автотесты, вы знаете боль [1]:
Координаты – это ад. Поменялось разрешение? Сломалось. Обновили интерфейс? Сломалось. Запустили на другой машине? Сломалось.
Селекторы – это тоже ад, но другой. XPath который работал вчера, сегодня не работает. #button-submit-form-container-wrapper-inner – и это реальный ID из продакшена.
Thick-клиенты – вообще беда. Офисные пакеты, всякие САПР, банковские клиенты. Selenium тут не поможет. Sikuli – костыль на костыле.
Порог входа – чтобы написать автотест, нужно быть программистом. QA-инженерам приходится учить Python/Java, а они хотят просто проверить, что кнопка работает.
Я работал в проекте, где были виртуальные рабочие места с кучей импортозамещённых приложений. Windows-окружение, куча legacy софта, ручной регресс занимал недели. И думал: “Должен же быть способ проще?”
Знаете, что меня удивляло на прошлых местах работы? Никто не делился своими наработками. Серьёзно. У кого-то был крутой скрипт для автоматизации – молчок. Кто-то запилил фреймворк – держит при себе.
Люди боялись. Боялись, что их легко заменят, если покажут свои инструменты. Ну, типа, если я раскрою свои секреты – меня выкинут первым при сокращении. Логика [2] понятная, но грустная.
Попытки улучшить общие процессы встречали холодно. “Зачем нам это, у нас и так работает”. Окей. В итоге приходилось собирать опыт [3] по крупицам из разных источников. Выдумывать решения самому. Делать инструменты в тишине, а потом показывать уже готовое.
Вроде ведь наоборот должно быть? Делиться опытом, учиться друг у друга, строить что-то совместно. Но нет. Если бы люди делились наработками – я бы запилил этот фреймворк на пару лет раньше. Точно.
С другой стороны – может, и хорошо, что пришлось делать с нуля. Хотя бы теперь хочется делиться открыто. Пусть даже через статьи и публикации в интернете.
Идея простая до безобразия: записал действия мышью и клавиатурой в JSON, потом проиграл обратно.
Но дьявол, как всегда, в деталях.
Вот как это выглядит схематично:

Проект состоит из двух частей:
1. Рекордер – записывает ваши действия
Запускаешь скрипт, жмёшь горячую клавишу – началась запись. Кликаешь мышкой, вводишь текст, жмёшь кнопки. Останавливаешь той же клавишей. Сохраняешь другой. Всё.
Фишка в том, что рекордер не просто пишет координаты. Он захватывает метаданные UI-элементов через Windows UI Automation:
{
"element": {
"name": "Сохранить",
"role": "button",
"bounds": [x, y, width, height]
},
"locators": [
{"type": "id", "value": "<element_id>"},
{"type": "role+name", "value": ["button", "Сохранить"]},
{"type": "path", "value": [
{"role": "window", "name": "<AppMainWindow>"},
{"role": "toolbar", "name": "<MainToolbar>"},
{"role": "button", "name": "Сохранить"}
]}
]
}
Это значит, что при воспроизведении раннер не тупо кликает по координатам. Он ищет элемент через UI Automation – сначала по идентификатору, потом по роли и имени, потом по пути в дереве интерфейса. Координаты – только запасной вариант.
2. Раннер – воспроизводит и проверяет
Раннер берёт JSON-файлы из указанной папки, последовательно их выполняет и собирает отчёт в HTML.
Вот что происходит при запуске теста:

Вот минимальный пример теста:
{
"name": "OpenHelpDialog",
"description": "Открыть меню Справка и проверить диалог",
"app": "<path_to_app>",
"window_pattern": ".*MainWindow.*",
"check_type": "window_exists",
"steps": [
{"action": "click", "target": "HelpMenu"},
{"action": "click", "target": "AboutItem"},
{"action": "wait", "duration": 0.2}
]
}
Читается как документация. Не нужен программист, чтобы понять, что тут происходит.
Windows – потому что там работает 90% нашего софта. UI Automation – родная технология, работает отлично через системную библиотеку.
Linux – потому что хотелось. Сделал базовую поддержку, но без UI Automation там всё хуже. Пока в статусе “работает, но не для прода”.
Офисные приложения и файловые менеджеры любят “думать”. Открываешь окно, а оно ещё 2 секунды дорисовывается. Кликаешь по кнопке, а UI-дерево меняется прямо во время клика.
Решение: таймауты и стабилизация.
Перед любыми действиями раннер ждёт, пока окно стабилизируется
Для окон с лентой первым действием кликаем главную вкладку – это стабилизирует активную панель
Между действиями – небольшая пауза по умолчанию
Звучит как костыль? Да. Но работает.
Открываешь файл, а там вылезает диалог “Включить макросы?” или “Обновление доступно”. Тест падает, потому что не ожидал этого окна.
Решение: паттерны вместо точных строк в заголовках окон.
"window_pattern": ".*<AppName>.*"
Этого хватает, чтобы найти окно, даже если заголовок содержит путь к файлу или версию приложения.
Windows – странная штука. Иногда окно “как бы” в фокусе, но клики не работают. Или фокус улетает на другой монитор (привет, RDP).
Решение: явная установка фокуса через системную библиотеку автоматизации. Плюс сохраняем идентификатор процесса, чтобы при повторном фокусе точно попасть в нужное окно.
Знаете, что меня удивило? Окна не ищутся по принципу “всё или ничего”. Раннер умеет находить “наиболее похожее” окно.
Реальность грязная. Заголовок окна постоянно меняется. То путь к файлу дописывается, то версия приложения. То локализацию поменяли. Если тупо требовать 100% совпадение – тесты падают каждый второй запуск.
Поэтому есть эвристики. Раннер смотрит на несколько признаков окна сразу. Какие-то важнее, какие-то менее. Выбирает окно, которое “больше всего похоже” на то, что записывали.
Пример. Записали тест для “Документ1.txt – Редактор”. Открыли “Документ2.txt – Редактор”. Тест находит окно. Потому что достаточно признаков совпало – это то же приложение, та же структура заголовка.
Или другое. Окно называлось “Settings”, стало “Настройки” после смены языка. Ок, заголовок не совпал. Но другие характеристики окна те же – раннер понимает, что это оно.
Это не магия. Иногда всё равно приходится обновлять метаданные. Но количество “упал непонятно почему” снижается за��етно. Тест стал терпимее к мелким изменениям.
Три способа ввести текст:
Через системные события – надёжно, но медленно. Хорошо для системных диалогов.
Через буфер обмена – быстро, но иногда фокус “уплывает” и текст вставляется не туда.
Эмуляция печати – средне по скорости, но ломается на нелатинице и спецсимволах.
Решение: умный режим. Раннер пробует методы по порядку: системные события → буфер → эмуляция. Первый, что сработал – и ок.
{"action": "input", "text": "<some_text>", "method": "auto"}
Версионирование – храним тесты в Git, видим изменения в diff
Модульность – один тест = один JSON. Легко комбинировать, переиспользовать
Отладка – открыл JSON, увидел шаг, который упал, поправил
Расширяемость – добавить новый тип проверки = добавить класс проверки в код раннера
Сначала я делал только визуальное сравнение. Снял эталонный скриншот, потом сравнил с текущим. Работает, но:
Медленно (скриншоты весят, сравнение тоже не быстрое)
Ложные срабатывания (сглаживание шрифтов, рендиринг, тени)
Хрупко (поменялась кнопка на 2 пикселя – тест упал)
Потом добавил UI-ассерты. Проверяем не “как выглядит”, а “что есть”.
Проверяет, что окно с нужными параметрами существует:
{
"check_type": "window_exists",
"window": {
"class": "<WindowClass>",
"title_pattern": ".*<AppName>.*"
}
}
Быстро, стабильно, не зависит от визуальных изменений.
{
"check_type": "checkbox_state",
"expected_state": "checked"
}
{
"check_type": "selected_value",
"expected": "Опция 1"
}
Автопроверка закрытых окон
Это мелочь, но приятная. Раннер сам отслеживает, какие окна ты закрывал во время теста. Alt+F4 нажал? Кнопку “Закрыть” кликнул? Запоминает.
После выполнения всех шагов автоматически проверяет – а закрылись ли они на самом деле? Не висят ли где-то в фоне?
Знаете, сколько раз у меня тесты “проходили”, а потом оказывалось, что приложение осталось открытым и жрёт память [4]? Теперь это ловится автоматом.
Проверки файлов
Не только UI. Можно проверить файловую систему.
“Этот файл должен появиться после теста”. “Этот должен измениться”. “А этот – остаться без изменений”.
Для тестов типа “Сохранить документ”, “Экспортировать отчёт” – незаменимо. Раннер снимает снимок файла до действий (хеш, размер, время модификации), потом проверяет после.
Пример из жизни. Тест “Сохранить как PDF”. Кликаем кнопки, вводим путь. Тест проходит. А PDF не создался – диалог закрылся, но сохранение упало молча. Раньше это находили только вручную. Теперь тест сам скажет “файл не появился”.
Fallback на координаты
Помните, я говорил про умный поиск через UI Automation? Так вот, если он не сработал – раннер откатывается на координаты.
То есть тест не падает сразу намертво. Сначала пытается найти элемент “правильно”, не получилось – кликает туда, куда записали при создании теста.
Да, координаты хрупкие. Да, могут не попасть. Но это лучше, чем сразу упасть с ошибкой [5] “элемент не найден”. Иногда это спасает.
Захват состояния без клика
В рекордере есть фича. Нужно зафиксировать состояние чекбокса, но не кликать по нему? Наводишь курсор, жмёшь специальную клавишу – рекордер запоминает состояние элемента под курсором.
Потом раннер проверит: “чекбокс должен быть включен, как записали”. Без лишних действий.
Раньше приходилось костылить – кликать, снова кликать, чтобы вернуть в исходное состояние. Теперь просто навёл и зафиксировал.
Для 80% тестов этого достаточно. Скриншоты оставил для случаев, когда нужно проверить внешний вид (дизайн, графики, кастомные контролы).
Бонусом прикрутил мониторинг системы. Во время выполнения тестов раннер собирает:
CPU и RAM в реальном времени
Топ процессов по потреблению ресурсов
Предупреждения, если CPU > 85% или RAM > 85%
Всё это попадает в HTML-отчёт. Удобно, когда тест упал не из-за бага, а потому что машина тормозила.
Отчёты формируются автоматически: таблица с результатами (зелёный/красный), скриншоты при фейлах, дифф-изображения, логи. Открываешь в браузере и сразу видно, что сломалось.
Я делал это для себя, но понял, что подходит для:
Импортозамещение – российские офисные пакеты и операционки. Всё это thick-клиенты, которые плохо автоматизируются стандартными инструментами.
Legacy Windows-приложения – банковские клиенты, CAD-системы, SCADA, старые ERP-системы.
Виртуальные рабочие места – образы с набором софта. Регресс-тестирование всего образа занимало недели. Теперь – часы.
Проекты без программистов – QA-инженеры могут записывать тесты сами, не зная языки программирования.
Окей, давайте про деньги и время. Потому что начальству обычно нужны цифры, а не “мне нравится этот подход”.
На прошлом проекте у нас был образ виртуального рабочего места. Десяток приложений, которые надо проверить перед релизом. Ручная проверка занимала у одного QA примерно 2 недели. Два человека – месяц работы на регресс. Каждый релиз.
С автотестами это сократилось до 3-4 дней. Где-то 60-70% экономии времени. Не идеал, но уже можно дышать. И это реальные цифры, не из презентации для инвесторов.
Знаете, что бесит руководителей проектов? Когда тесты пишет один автоматизатор на всю команду. Он становится бутылочным горлышком. Заболел, ушёл в отпуск, уволился – всё, автотесты стоят.
Тут другая история. QA-инженер записывает тесты сам. Без кода. Нажал кнопки, сохранил JSON, готово. Порог входа низкий. Не нужно учить Python полгода. Это разгружает автоматизаторов и даёт QA больше независимости.
У нас был случай. Обновили интерфейс – поменяли расположение кнопок. Selenium-тесты полегли пачкой. Автоматизатор две недели чинил XPath и CSS-селекторы. Две недели!
С этим фреймворком быстрее. Элементы ищутся через UI Automation – по роли, имени, идентификатору. ��сли кнопка “Сохранить” переехала на другое место, но осталась кнопкой “Сохранить” – тест найдёт её. Иногда вообще ничего править не нужно. Иногда – минут 10 на пачку тестов.
Раньше толстые приложения либо не тестировали автоматически вообще, либо пытались костылями типа Sikuli. Скриншоты, поиск по картинкам – это всё работает через раз и ломается от малейших изменений.
Здесь автоматизация через системный UI Automation. Тот же подход, что в Selenium, но для десктопа. Это открывает автоматизацию для целого пласта приложений, которые раньше были “вне зоны доступа”. Офисные пакеты, CAD, банковские клиенты, всякие SCADA.
Простая математика [6]. Раньше: регресс 2 недели → блокирует релиз → релиз раз в месяц, если повезёт. Теперь: регресс 3 дня → можно выпускать каждую неделю. Или чаще.
На практике видел ускорение в 2-3 раза точно. Где-то доходило до 5 раз, но там много факторов. Зависит от того, сколько у вас вообще ручных проверок было.
Знаете эту боль? Тест то падает, то проходит. Без причины. Проверили вручную – всё работает. Перезапустили тест – прошёл. Это выматывает. Команда перестаёт доверять автотестам.
Тут стабильнее, потому что поиск через UI Automation менее хрупкий, чем клики по координатам или по сложным XPath. Не идеально, конечно. Бывают зависания окон, медленные приложения. Но в целом процент ложных падений ниже.
Если у вас проект с российским софтом или переход на него – это больная тема. Многие инструменты заточены под западные продукты. А тут можно тестировать отечественные офисные пакеты, операционки, что угодно. Работает на Windows, есть базовая поддержка Linux.
Для компаний, которые строят решения на импортозамещении – это не просто удобно, это критично. Потому что альтернатив мало.
Автотесты можно гонять прямо внутри виртуальных машин и VDI-сред. Проверили образ, зафиксировали результат. Не нужно разворачивать тестовые стенды на физических машинах. Всё внутри виртуалки.
Для компаний с большими парками виртуальных рабочих мест (банки, госсектор, корпорации) – это экономия инфраструктуры и времени на подготовку окружения.
Давайте грубо прикинем. Команда из 10 QA. Половина времени – ручной регресс. Средняя зарплата – ну, сами знаете. Экономия 50-70% времени на регресс = можно либо меньше людей нанимать, либо те же люди делают больше полезной работы (исследовательское тестирование, улучшение процессов).
Плюс ускорение релизов. Быстрее релизы – быстрее фичи до пользователей – быстрее обратная связь. Это уже влияет на продукт.
Плюс снижение рисков. Меньше багов доходит до прода, потому что регресс теперь гоняется чаще и стабильнее.
Всё это конвертируется в деньги. Не сразу, но конвертируется.
python recorder.py
Горячая клавиша 1 – старт/стоп записи
Горячая клавиша 2 – вставить паузу
Горячая клавиша 3 – пометить момент для финальной проверки (захватит метаданные окна)
Горячая клавиша 4 – захватить метаданные под курсором без клика (для чекбоксов, списков)
Горячая клавиша 5 – завершить и сохранить
Файл сохраняется в JSON, можно сразу запускать.
python runner.py
Раннер собирает все JSON из указанной папки, выполняет по порядку, формирует отчёт.
[INFO] Выполняется тест: test_file_manager.json
[INFO] Запуск приложения: <app_path>
[INFO] Окно найдено: <WindowTitle>
[INFO] Выполнение действий: 2 шага
[INFO] Шаг 1/2: клик по координатам [x, y]
[INFO] Шаг 2/2: клик по координатам [x, y]
[INFO] Проверка: window_exists -> PASS
[SUCCESS] Тест пройден: test_file_manager.json
Всё прозрачно. Если упало – видно на каком шаге.
Сейчас фреймворк работает, но есть идеи, как сделать его умнее.
Вот как AI может помочь:

Представьте: запускаете приложение, говорите “создай тест, который откроет файл и сохранит его”. AI анализирует UI-дерево, находит нужные элементы, генерирует JSON. Уже экспериментирую с мультимодальными моделями для распознавания интерфейсов.
Тест упал, потому что кнопка переехала? AI может попробовать найти её по похожему имени или роли, обновить метаданные и продолжить. Это снизит количество ложных падений.
Есть приложения, которые рендерят UI в Canvas или Direct3D. UI Automation их не видит. Тут нужны OCR + компьютерное зрение [7]. Можно натравить модель на скриншот и спросить: “где тут кнопка Сохранить?” Получить координаты, кликнуть.
Мечта: записать 500 тестов один раз, потом гонять их каждый билд. Регресс из недель превращается в часы. Уже работает, но нужно масштабировать.
Я не хочу продавать вам идею, что это решает все проблемы. Нет.
Минусы:
Всё ещё зависит от координат в крайних случаях (когда UI Automation не помогает)
Windows-центричность (Linux-поддержка сырая)
Не подходит для веб-приложений (там Selenium/Playwright лучше)
Нужно записывать тесты вручную (хотя это быстрее, чем писать код)
Плюсы:
Низкий порог входа (записал, проиграл, готово)
Работает с thick-клиентами, где ничего другое не работает
JSON понятен не-программистам
Стабильнее, чем клики по координатам (благодаря UI Automation)
Это не замена Selenium. Это инструмент для другой задачи – автоматизации десктопных приложений, которые игнорируются в мире автотестов.
Автор: Babaji
Источник [8]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/21964
URLs in this post:
[1] боль: http://www.braintools.ru/article/9901
[2] Логика: http://www.braintools.ru/article/7640
[3] опыт: http://www.braintools.ru/article/6952
[4] память: http://www.braintools.ru/article/4140
[5] ошибкой: http://www.braintools.ru/article/4192
[6] математика: http://www.braintools.ru/article/7620
[7] зрение: http://www.braintools.ru/article/6238
[8] Источник: https://habr.com/ru/articles/966756/?utm_source=habrahabr&utm_medium=rss&utm_campaign=966756
Нажмите здесь для печати.