Автоматизация тестирования во flash-играх

Каждый, кто так или иначе занимался тестированием flash-приложений, хоть раз, но сталкивался с рутинной ручной работой в процессе и однажды, в приступе поиска конструктивного решения, забивал в поисковик что-то типа "автоматизация flash" в различных вариациях. Если вы читаете эту статью, надеясь таки найти ответ на сей сакраментальный вопрос, значит вы, как и я, не нашли ответа у великих и могучих гугля и яндекса. Все, что можно найти по этой теме - связки различных инструментов (трудно настраиваемые и поддерживаемые), либо заточенные лишь под свой проект решения программистов для облегчения жизни тестерам своего же проекта. Я не буду делать краткий обзор неподошедших, но подававших надежды инструментов, вы и без меня их наверняка перепробовали. Я хочу познакомить вас с Genie.

Automated UI Tester for Adobe® ActionScript® is code named as Genie.

Не знаю, что сподвигло ребят из Adobe создать этот инструмент и почему они его не раскручивают, но это - единственное готовое и не требующее особых навыков в извращениях решение.  Для затравки я опишу что он может, покажу пару примеров. Genie уникален - он создан для флеша, не требует доступа к исходному коду или запуска внутри приложения, может запускаться в фоне. Его отличительной способностью является умение однозначно определять любой элемент внутри флеша (epic win!). Можно записывать произведенные действия скриптами и запускать их! Правда, после доработки напильником, но по сравнению с тем же Sikuli (сразу оговорюсь, что ничего не имею против самой проги - она отлична и достойна похвал, но для флеша её ценность стремится к нулю), это просто песня. Т.е. вы просто поднимаете у себя Genie, запускаете вашу SFWку, коннектитесь к ней, записываете скрипты, если надо - допиливаете и ваши тесты готовы. Конечно, есть нюанс для тех, кто не имеет навыков программирования - скрипты пишутся на Java, шлифовать их без программиста будет... Ну вы поняли.

Genie - это эклипсовый плагин, т.е. основная работа будет в Eclipse. После поднятия (это не установка в прямом смысле этого слова) Genie и открытия Eclips'а вы увидете панельку с инструментами:

 

Основные элементы, используемые в работе (оговорюсь, что "названия" им давала я, т.к. в англ. документации они просто описаны свойствами): Лупа, Кисть, Линейка, Камера, Запрос свойств объекта, Обновление дерева. Остановлюсь на каждом из них подробнее. 

Лупа. Ищет компонент в дереве. Я уже упоминала, что Genie однозначно определяет все элементы внутри flash'а - на практике это означает, что Genie каждому элемента внутри SWFки присваивает свой уникальный ID - genieID. Пессимисты могут подозрительно спросить - не меняется ли этот ID после перезапуска? Нет, не меняется, он статичен и присваивается не хаотически, а связан с кодом клиента. В противном случае Genie был бы довольно бесполезен. У Лупы есть 2 состояния - первое - позволит найти объект и провзаимодействовать с ним (скликнуть) и второе - кликнет на объект, но без взаимодействия - оно нужно, если вам нужно найти его в дереве, но не скликивать из рабочей области. К примеру, в HOG сцене ( (Hidden Object Game - игры, где на картинке нужно найти заданные объекты) мне нужен ID элемента, но если я кликну на него с взаимодействием (первое состояние), то объект будет отмечен как найденный и просто "уйдет" со сцены, что, мягко говоря, неудобно, если с ним требуется дальнейшая работа. В этом случае второе состояние поиска просто незаменимо. Третье нажатие на Лупу отключит поиск.
**Кисточка** позволит нам подстветить в SWF выбранный в дереве объект. Просто выделите объект, кликните на кисточку и в SWF вы увидите, что он выделился красным контуром:


Линейка позволит получить локальные координаты выбранного объекта. Честно говоря, не пользовалась и в моем случае координаты - не совсем то, к чему хотелось бы привязываться, но все равно круто. Панель с координатами появится в SWF прямо под значком Genie, водите по объектам, а в панельке показываются цифры.


Камера делает скриншот, через который тоже можно будет обратиться к элементу, указав путь и степень толерантности (точность совпадения, с которой будет сравниваться указанный рисунок с искомым на экране - от 0 до 100, чем ниже толерантность, тем точнее Genie будет пытаться определить объект). Эта функция очень удобна, если вдруг в игре или на экране имеется HTMLный элемент, к которому необходимо обратиться. Нужно отметить, что не стоит увлекаться чрезмерной точностью совпадения - при достаточно высокой толерантности Джин может просто не найти объект, соотвественно, при низкой - кликнуть не на тот, что нам нужен. Область скриншота лучше брать с захватом побольше - выше вероятность, что будет кликнут именно указанный, а не похожий объект. Как пользоваться камерой: жмем на значок, затемняется область и появляется крестик, выделяем нужную нам область и после отжатия клавиши мыши будет показано окно с рисунком и кнопками:

Сохранить понятно что делает, Recapture переснимает, с закрытием тоже понятно, а Add Hotspot добавляет на рисунок область, непосредственно в которую будет сделан клик. Т.е. по умолчанию клик буден сделан в центр, но если нам нужно кликнуть на кнопку, которая на рисунке не в центре, то просто задаем “горячую точку” и можем не беспокоится.

Добавить в скрипт клик на указанный рисунок можно используя класс функций Com.adobe.genie.executor.uiEvents.UIImage, например:

new UIImage().clickImage(String imagePath , int… tolerance) 
new UIImage ().clickImageHotspot (String imagePath , int… tolerance)

Запросить свойства объекта (Request Genie Properties of Object) вот та функция, которая пригодится нам в случае, когда просто Property не показывают последние изменения в SWF. К примеру, у меня меняется плашка в SWF, а Genie в свойствах показывает старый текст, нажимаем “Запросить свойства объекта” и получаем развернутый список, где поле text уже обновлено и содержит текущий текст.

Обновить дерево объектов - ну тут понятно, обновляется дерево, однако иногда это не помогает получить обновленные свойства и их нужно запрашивать предыдущей кнопкой.
И наконец несколько пунктов, которые не вынесены на панель, а появляются по клику на стрелочку:


Hide Genie Icon убирает значок UT с флешки (иногда здорово мешает), минус в том, что только на время пока запущен Эклипс. Впрочем, иногда в разных браузерах значок сам отваливается.

Record Script At Application Pace скрипт будет записан с простоями, т.е. ваши паузы будут учтены в виде wait’ов

Disconect SWF с этим все ясно, отсоединиться от флешки.

Find component by GenieID тоже не требует особых пояснений.

Save Tree XML in File ясно что делает, но у меня не открылось сохраненное дерево, увы. Может кто-то лучше меня разбирается что с этим потом делать, поделитесь.

Итак, теперь, с основными функциями разобрались. Что нужно, что бы записать простой скрипт с Geine? Запущенный сервер, Эклипс и зеленый треугольник UT на флешке (не забываем коннектиться к SWFке - подробно о том, как поднять - в хелпе, если нужно будет - я напишу подробно на русском как). Жмем на значок и запись скрипта пошла! При этом значок становится красным квадратом (ВНЕЗАПНО!), при нажатии на кортоый запись, соответственно, прекращается. Но об этом чуть позже.

Если перед записью скрипта мы выбрали в выпадающем меню пункт “Запись с тупняками” (Record Script At Application Pace), то все задержки между кликами будут учтены в скрипте. Запишем что-нибудь самое простецкое, закрытие входных pop-up’ов. Загружаем игру и когда появляется газета, запускаем запись. Покликали, закрыли и остановили. После остановки записи Джин любезно вываливает на окошко с телом скрипта и кнопками “скопировать” и “закрыть” - наше дело сохранить этот скрипт либо в файлик, либо пока прямо в панель Эклипса со скриптами. Получится примерно такое:

    package scripts;
    import com.adobe.genie.genieCom.SWFApp;
    import com.adobe.genie.executor.GenieScript;
    import com.adobe.genie.executor.components.*;
    import com.adobe.genie.executor.uiEvents.*;
    import static com.adobe.genie.executor.GenieAssertion.*;
    import com.adobe.genie.executor.enums.GenieLogEnums;
    
    /**
     * This is a sample Genie script.
     *
    //Change name of the class
    public class Unnamed extends GenieScript {
    
    public Unnamed() throws Exception 
    { 
    super();
    }
    
    @Override
    public void start() throws Exception {
    //Turn this on if you want script to exit
    //when a step fails
    EXIT_ON_FAILURE = false;
    //Turn this on if you want a screenshot
    //to be captured on a step failure
    CAPTURE_SCREENSHOT_ON_FAILURE = false;
    
    SWFApp app1=connectToApp("[object Preloader]");
    (new GenieDisplayObject("SP^NewspaperPopup:::FP^NEWSPAPER:::SE^closeBtn::PX^0::PTR^0::IX^9::ITR^0",app1)).click(7,11,704,60,0,0,3,false);
    (new GenieMovieClip("SP^MessageWindow:::FP^CloseButton:::SE^htmc::PX^25::PTR^0::IX^1::ITR^0",app1)).click(27,18,740,22,0,0,3,true);
    }
    }

Если аргументы click оставлять пустыми, то нажатие будет выполнено без подведения курсора на элемент. Теперь для того, чтобы запустить наш скрипт, нам понадобится сбросить его в текстовый файлик, обозвать его xxx.java (где xxx должен быть такой же, как и Unnamed - не забыть задать имя в теле скрипта), открыть в эклипсе. Если есть ошибки, редактор эклипса их выделит (в готовом скрипте ошибок конечно нет, но при модификации мы вполне можем что-нибудь напортачить). Следующий этап запуска - выбрать пункт Run Configuration… и в открывшемся окне в пункте New configuration во вкладке Arguments в доме, который построил Джек </s< строке Program Arguments указать перед .class имя скрипта (оно же имя из public class Unnamed extends GenieScript и

public Unnamed() throws Exception:

Т.е. если у меня скрипт называется MC, но и в теле скрипта тоже стоит MC и в классе тоже MC. Возможно, для программистов это очевидно, но я в этом объезьяна - как написано в документе, так и описываю :slight_smile: После этого кликаем Run и переходим к нашей флешке. Во время выполнения скрипта значок на SWFке вверху меняется на красный треугольник без фона.

Как видно, сам кусочек с кликами занимает всего ничего - закрыли пару окон, получили пару строчек. Но это если нам нужно сделать всего пару действий, при более сложных задачах конечно конструкции становятся сложнее. К примеру, скрипт на прохождение HOG-сцены включал в себя считывание текста с плашки, сопоставление текста с соответствующим ему объектом и клик уже непосредственно по идентифицированному объекту. Предметов в HOGe у нас от 60 до 75, для каждой сцены приходилось делать такие библиотеки со связками “текст-объект”. Таким образом. записывая скрипты и допиливая их, можно добиться неплохих результатов. Может быть умельцы смогут соединить Genie с Selenuim’ом, было бы интересно ознакомиться с таким опытом.

P.S. FAQ по продукту тут, скачать тут, документация вот.

P.P.S огромное спасибо за наводку и консультации Brit

2 лайка