python

AirTest IDE и Image Recognition — автоматизация тестирования мобильных игр на основе распознавания и

  • пятница, 9 августа 2019 г. в 00:20:10
https://habr.com/ru/post/462587/
  • Python
  • Unity
  • Тестирование мобильных приложений
  • Тестирование игр
  • Unreal Engine


В предыдущей статье мы познакомились с AirTest IDE, но, на всякий случай, давайте повторим: AirTest IDE разработан компанией NetEase и предназначен для "hard-to-automate" приложений, таких как, например, игр. Собственно на них и делается основной упор разработчиками, хотя это не мешает использовать AirTest и для любых других приложений.


Сегодня же я расскажу вам об одном из 2х основных фреймворков — AirTest. AirTest — это кросс-платформенный фреймворк для автоматизации UI, основанный на принципах распознавания изображений (Image Recognition), который, как заявляют разработчики, подходит для игр и приложений. AirTest Project на GitHub содержит 4 проекта: Airtest, Poco, iOS-Tangent, multi-device-runner.


А теперь давайте перейдём к самому интересному!


image


Как работает AirTest


AirTest обрабатывает полученные скриншоты на основе процесса thresholding. Суть заключается в том, чтобы сравнить интенсивность пикселей на изображении с некоторым числом (threshold value) и, если значение пикселя больше, то назначить ему цвет (чаще всего используется белый). В противном случае назначается другой цвет — чёрный. Как итог, на выходе получаем черно-белое изображение. Из этого следует естественное ограничение — AirTest не учитывает цвет во время распознавания. К примеру, если у вас используется объект с одним и тем же силуэтом, но разной, к примеру, раскраской и вам нужно проверить наличие элемента именно с определенной цветовой палитрой, то это будет крайне затруднительно, а может и не сработает вовсе.


К примеру в рамках пробы AirTest IDE было решено поработать с игрой Marvel Puzzle Quest. При загрузке персонажи с данной комикс вселенной мелькают на экране в определенном порядке. Время от времени у них меняются костюмы и это впервые насторожило меня. В примере ниже я ожидал, в рамках теста, Человека Паука в классическом, а получил в стелс костюме. Тест, собственно, прошёл успешно, а произошло это по причине описанной выше — использование чёрно-белого изображения во время распознавания. Пример того, что ожидалось и что, в итоге, получилось:


image


Улучшение вероятности успешного завершения тестов


Как вы уже поняли, Image Recognition — это далеко не панацея, хоть и работает здесь он хорошо. Для написания качественных тестов вам не избежать написания кода и, соответственно, знания основ Python. К примеру прежде чем искать конкретный элемент, неплохо было бы убедиться, что он действительно есть на экране. Бывают случаи, когда AirTest "промахивается" и может принять неправильный элемент за тот, что нужен вам. Время от времени бывают проблемы с распознаванием текста, который вы хотите найти при помощи Image Recognition. AirTest может спутать результаты и считать, что нужный вам текст есть на экране, но, на самом деле, текст там совершенно другой. Процесс анализа результатов призвана упростить система генерации отчётов, которая уже встроена в AirTest IDE. Создать и открыть отчёт можно после завершения теста/скрипта при помощи сочетания клавиш Ctrl/Cmd+L.


По общим рекомендациям я бы выделил ещё и следующее.


  • Делайте скриншоты именно тех элементов, которые вам нужны. Я имею в виду, что если вам нужна кнопка, которая, к примеру, находится на сложном текстурном заднике, то постарайтесь сделать скрин только кнопки, чтобы не тратилось время на обработку задника, который, по сути, вам не нужен. В таком случае поиск не будет зависеть от того, что изображено на заднике и вы получите более точный результат за меньшее время.
  • Постарайтесь избегать распознавания изображений на которых присутствует только текст, т.к. успешное распознавание ("success rate") в таком случае будет сильно снижено.
  • Хоть создание скриншотов во время автоматической записи кода (script auto recording) является достаточно удобной функцией, но, местами, скриншоты создаются не очень информативными. Лучше создавать их вручную, чтобы хранить в ваших картинках больше полезной информации для поиска.

И если вы хотите спросить "Возможно ли изменить настройки процесса поиска изображений?", то я вам отвечу — да, это возможно.


Настройки поиска изображений (Image Recognition)


Пользователю позволено и рекомендуется работать с настройками Image Recognition, чтобы добиться нужных результатов, оптимизировать время и вероятность успешного распознавания элементов (success rate) на экране. Эти настройки хранятся в окне Image Editor и, чтобы открыть его, вам нужно дважды кликнуть на нужное изображение в Script Editor. Настройки распознавания каждой картинки нужно менять отдельно либо использовать глобальные переменные, если, к примеру, вы хотите увеличить требования к точности threshold операции для вашего проекта.


Окно Image Editor

image


Image Editor содержит в себе рабочую зону, а также "Snapshot+Recognition" и "Show Help" кнопки. Первая отвечает за сравнение вашей текущей картинки со snapshot версией. Snapshot картинка захватывается с текущего окна на вашем девайсе. Вторая кнопка открывает мануал по функционалу Image Editor. В правой части окна отображается текущая картинка для поиска, а также такие настройки как filename, threshold, target_pos и rgb.


  • filename поле отвечает за имя текущего сохраненного изображения (все картинки сохраняются в папке проекта).
  • threshold хранит в себе значение процента совпадения (от 0 до 1) изображений после распознавания. Чем выше значение, тем выше требование к точности сопоставления изображений. Как упоминалось выше, AirTest преобразует изображения в оттенки черно-белого (в зависимости от реализации threshold) и, следовательно, цвет не учитывается во время распознавания.
  • rgb чекбокс призван "включить и добавить" цвет во время распознавания изображений и, тем самым, начать учитывать его. Однако учитывайте, что включение данного функционала всё равно не гарантирует 100% результата. К примеру, если у вас есть 2 одинаковых кнопки, которые различаются только цветом заднего фона, вероятность некорректного распознавания (например в рамках assert_exists/assert_not_exists) будет достаточно велика.
  • target_pos отвечает за точку на картинке на которую AirTest нажмет после распознавания. По умолчанию значение равно 5, но вы можете изменять его от 1 до 9, где 1 — это левый верхний угол вашего рабочего изображения, а 9 — правый нижний угол. Местоположение всех девяти точек наглядно изображено на скриншоте ниже. Также вы можете почитать об этом в официальной документации
    В данном примере для распознавания выделена средняя кнопка. Контур показывает границы выделения.

image


Написание автоматизированных тестов при помощи AirTest


Все рабочие команды фреймворка AirTestможно найти в окне AirTestAssistant в левом верхнем углу Airtest IDE. Если его нету, то можете выставить расположение окон по умолчанию при помощи Window -> Default layout.


Местоположение окна AirTest Assistant

image


В текущей версии программы вы можете пользоваться следующими командами, которые доступны в окне AirTest Assistant:


  1. touch — данная команда имитирует touch жест на мобильном устройстве. Touch имеет следующие параметры — touch(v, times=1, duration=0.01, right_click=False).
    • v — картинка или координата (x,y)
    • times — количество нажатий. По умолчанию значение равно 1
    • duration — продолжительность удержания после касания экрана. При помощи этого параметра можно имитировать"долгое нажатие" (long_touch). Значение по умолчанию равно 0.01 секунды
    • right_click — нажатие "правой кнопки мыши". Может быть использовано только в для Windows программ
  2. wait — ожидание UI элемента. Команда имеет следующие параметры — wait(v, timeout=TIMEOUT, interval=5, intervalfunc=None).
    • v — изображение, которое ожидает программа
    • timeout — время ожидания. Значение по умолчанию равняется 20
    • intervalfunc — пользовательская (кастомная) функция. Если изображение не найдено, то будет выполнена эта функция
    • interval — интервал между сравнением изображений
      Функция возвращает следующее: если изображение найдено, тогда возвращаются координаты центра данного изображения, иначе выбрасывается TargetNotFoundError
  3. swipe — данная команда имитирует swipe жест на мобильном устройстве ("проведения пальцем по экрану"). Swipe имеет следующие параметры: swipe(v1, v2=None, vector=None, duration=0.01).
    • v1 — значение с которого начинается свайп. Может быть как изображением, так и заданной координатой (x, y)
    • v2: значение окончания свайпа (команда выполняется с v1 до v2). У данного параметра приоритет выше, чем у параметра "vector"
    • vector[x,y] — создается во время работы AirTest или же можете задать его самостоятельно. Указывает в какую сторону нужно свайпнуть. Чтобы свайпнуть вправо, X должен быть положительным, в свою очередь Y должен иметь положительное значение для свайпа вниз.
    • steps — не пользовался данным параметром и не нашел как он применяется на практике. Плашка с подсказкой выдаёт следующее: "the node in the swipe path, default 5". Предположу, что вектор направления свайпа будет разделен на "секции" и вместо того, чтобы свайпнуть мгновенно из точки А в точку Б, будет сымитирован свайп с небольшими паузами в нодах, указанных в данном параметре, как бы имитируя поэтапное перемещение. К примеру если значение равно 5, значит вектор будет разделен на 5 отрезков.
    • duration — длительность свайпа. Значение по умолчанию равно 0.5 секунды
  4. exists — проверка существует ожидаемый вами элемент на экране монитора устройства. exists имеет следующие параметры: exists(v)
    • v — изображение
      Функция возвращает следующее: если изображение найдено, тогда возвращаются координаты центра данного изображения, иначе возвращается False.
  5. text — команда ввода текста. text имеет следующие параметры: text(text, enter=True, search=False)
    • text — текстовая строка, которую нужно ввести
    • enter — данный параметр отвечает за то, нужно ли использовать "Enter" после ввода текста. Значение по умолчанию — True
    • search — не пользовался данным параметром и не нашел как он применяется на практике. Плашка с подсказкой выдаёт следующее: "force "Search" or not after input". Значение по умолчанию — False
  6. keyevent — эмулирование нажатия физических кнопок на устройстве, таких как HOME, BACK, MENU, POWER и т.д. Параметры для данной команды: keyevent(keyname)
    • keyname — название кнопки (POWER, HOME и т.д.)
  7. snapshot — создание скриншота экрана в текущем состоянии. Параметры по умолчанию: snapshot(filename=None, msg="test-point")
    • filename — сохранить текущий скриншот как отдельный файл. Можно проигнорировать данный параметр.
    • msg — описание данного тестового поинта. Этот текст будет отображен в HTML отчете, который можно создать после окончания теста.
      Данная функция возвращает следующее: имя файла (filename).
  8. sleep — запущенный тест "засыпает" на некоторое время. Значения по умолчанию: sleep(secs=1.0)
    • secs — время ожидания. Значение по умолчанию равно 1 секунде.
  9. assert_exists — проверка, существует ли элемент. Параметры для данной команды: assert_exists(v, msg="test-point")
    • v — изображение с элементом, наличие которого проверяется
    • msg — описание данного тестового поинта. Этот текст будет отображен в HTML отчете, который можно создать после окончания теста
      Данная функция возвращает следующее: если изображение найдено, то возвращаются координаты центральной точки данного изображения, иначе выпадает AssertionError
  10. assert_not_exists — проверка, что элемент не присутствует на экране устройства. Параметры для данной команды: assert_not_exists(v, msg="test-point")
    • v — изображение с элементом, наличие которого проверяется
    • msg — описание данного тестового поинта. Этот текст будет отображен в HTML отчете, который можно создать после окончания теста
  11. assert_equal — проверка, что атрибут равен заданному значению. Параметры для данной команды: assert_equal(first, second, msg="test-point")
    • first — первый элемент для сравнения
    • second — второй элемент для сравнения
    • msg — описание данного тестового поинта. Этот текст будет отображен в HTML отчете, который можно создать после окончания теста
  12. assert_not_equal — проверка, что атрибут не равен заданному значению. Параметры для данной команды: assert_not_equal(first, second, msg="test-point")
    • first — первый элемент для сравнения
    • second — второй элемент для сравнения
    • msg — описание данного тестового поинта. Этот текст будет отображен в HTML отчете, который можно создать после окончания теста

Данные команды разделены на 3 основные группы: Операции (Operations), вспомогательные функции (Auxiliary functions) и проверки (Assertions). Вы можете выбрать нужную вам группу при помощи соответствующего фильтра (выпадающее меню сразу под названием окна).


Фильтр групп команд

image


Команды, которым необходимо изображение, активируют функции записи скриншота сразу после нажатия на соответствующую кнопку. К примеру, чтобы выбрать на какой элемент нажать на экране, выберите команду touch в AirTest Assistant и в окне Device Screen, на активном устройстве, обведите нужный для нажатия элемент. После этого в главном окне (Script Editor) появится соответствующая команда, в нашем случае touch, с изображением в качестве параметра. Как итог, процесс автоматизации выглядит следующим образом (гифка записана с устаревшей версии AirTest IDE):


image


Если вы по какой-то причине не хотите вручную создавать скриншоты и\или в целом писать код, то можете воспользоваться функцией автоматической записи. Активировать её можно при помощи нажатии на кнопку "камеры" напротив выпадающего меню с группами команд в окне Airtest Assistant. Автозапись — штука достаточно точная и удобная, но, само-собой, не является панацеей и не заменит ручного набора кода.


image


Стоит упомянуть ещё 3 горячие клавиши — F5 (запуск скрипта), F10 (остановка запущенного скрипта), Ctrl+L/Cmd+L (создание отчёта на основе законченного теста).
Запускать готовые тесты можно и без UI, используя терминал (command line). Больше информации об этом в целом и о запуске тестов в частности можно найти здесь.


Пример отрывка теста, написанного при помощи AirTest фреймворка можно найти под спойлером!


Пример автотеста написанного при помощи AirTest (Image Recognition)

image


Само-собой UI в вашем приложении/игре не состоит сплошь и рядом из уникальных иконок, кнопок, задников и т.п. Плюс ко всему периодически визуально идентичные элементы могут встречаться на одном экране, например кнопки, слайдеры и т.д. Чаще всего в таких случаях AirTest не сможет распознать нужный вам элемент и, либо тест упадет с ошибкой, либо будет выбран неверный элемент интерфейса для дальнейших манипуляций.


Пример окна с несколькими идентичными элементами

image


Специально для таких случаев был разработан ещё один фреймворк, который уже встроен в AirTest IDE. Он Poco и вкратце о нём уже было рассказано в статье с общим обзором Airtest IDE. Подробнее же о данном фреймворке я расскажу в следующей статье.


Расскажите, пользовались ли вы уже AirTest IDE и что вы думаете о данном инструменте. Буду рад обсуждению в комментариях!