Qa Без Рутины: Как Мы Автоматизировали Регрессионное Тестирование

Всем привет, меня зовут Александр Мастюгин, я работаю тестировщиком в студии Норд. В IT-сфере бытует предубеждение, что работа тестировщиком — утомительное и монотонное занятие.

Но я с этим не согласен: на мой взгляд, это творческая, техническая и исследовательская деятельность.

Чтобы хорошо выполнить эту работу, нужно погрузиться в задачу, разобраться во всех ее тонкостях, сложностях, разобраться, какие подводные камни в ней есть.

Но справедливости ради надо сказать, что есть еще скучный момент – это регресс.

Чтобы минимизировать его роль в рабочем процессе и, соответственно, избавиться от рутины, мы в студии Nord решили автоматизировать регрессионное тестирование.

В этом тексте я расскажу вам, что мы сделали.



QA без рутины: как мы автоматизировали регрессионное тестирование



Автоматизация механики автобатлера

Мы разрабатываем игру Hustle Castle. Это мобильный автобатлер с элементами экономической стратегии и РПГ.

В качестве движка используется Unity, а сервер написан на Java. Основная механика автобоя такова: игрок и отряды противника противостоят друг другу, все персонажи имеют специальное снаряжение, дающее им способности, а сам бой автоматический — пользователю остается только произносить заклинания и использовать таланты своего героя.

В Hustle Castle также есть замок с кучей комнат, где можно добывать ресурсы, создавать предметы и так далее.

Также в игре присутствует сетевая механика с кланами, развитием территорий, ареной и многим другим.

И все это сосуществует друг с другом и подчинено общей логике.

С описанием Hustle Castle мы закончили, теперь можно перейти к более глубоким вещам.

Геймплей в игре завязан на способностях юнитов.

С технической точки зрения способность — это некая сущность, имеющая множество настроек: как и когда она будет активирована, на кого она повлияет, какой эффект она имеет, какие еще способности она может активировать и так далее.

Мы описываем поведение каждой способности в виде объектов Json. Есть простые способности, а есть структурные — они позволяют последовательно или параллельно активировать другие способности.

Кроме того, существуют различные типы способностей, такие как контратаки, баффы, оглушения.

В общем, там много разных настроек.

Все это учитывается алгоритмом автобоя.

Если сильно упростить, то вот как это работает. На входе есть какие-то данные — это состояние наших бойцов: какие у них характеристики, какие у них способности.

Переносим эти данные в калькулятор боя, который делает все расчеты.

На каждом шаге расчетов он сообщает, какое событие произошло, активировал ли он какую-либо способность или нанес ли урон.

После полного цикла вычислений получаем результат боя.



QA без рутины: как мы автоматизировали регрессионное тестирование

Стоит отметить, что код калькулятора боя доступен как на клиенте, так и на сервере.

Это необходимо для проверки результатов боя — оказывается, что и клиент, и сервер, и калькулятор боя смотрят на одни и те же данные.

Для автоматизации автоматической проверки боя мы решили сделать собственный клиент, который сможет на основе входящих данных формировать запрос к серверу на получение начального состояния боя.

Автотесты используют этот клиент, получают состояние, отправляют его в калькулятор, подписываются на событие нового шага расчета, а затем проверяют условия на каждом шаге.



QA без рутины: как мы автоматизировали регрессионное тестирование

Средний тест нашей боевой системы Для проверки механики боевой системы мы используем способности, собранные специально для тестирования.

Испытания направлены на механику; мы не проверяем способности к продажам тестами.

Мы также используем этот подход в нашем внутреннем продукте под названием «Battle Chaser».

Нашим геймдизайнерам это нужно для баланса боевой системы.

Геймдизайнер может взять из производства любые состояния игрока, объединить их в тестовые группы, при желании заменить одни способности на другие и провести тестовый прогон на большом количестве боёв.

По результатам прогона геймдизайнер получает статистику боя.

Это был первый шаг к автоматизации.

Наши автотесты дают нам уверенность в том, что базовая логика калькулятора боя не сломалась после действий геймдизайнеров и разработчиков.

Это сложная вещь, для которой, к сожалению, у нас нет юнит-тестов.

Поэтому эти автоматические тесты боевого калькулятора — наша единственная возможность убедиться, что большая часть боевой системы работает стабильно.



Тесты на сервере и клиенте

Чтобы объяснить, что будет дальше, обратимся к теории — перед вами всем известная пирамида тестирования.



QA без рутины: как мы автоматизировали регрессионное тестирование

Суть пирамиды проста.

Чем ближе мы ко дну, тем дешевле и быстрее тесты.

И наоборот – чем выше, тем дольше и дороже.

Решение кажется очевидным — нужно использовать юнит-тесты как самые быстрые и дешевые.

Но все немного сложнее.

Чтобы разработчики могли писать модульные тесты, приложение должно иметь определенный дизайн — оно должно быть тестируемым.

И, к сожалению, у нас это есть не везде.

Модульных тестов для серверной логики почти нет, а те, что существуют, представляют собой компонентные тесты, которые в основном охватывают подбор игроков, базовую логику режимов и функций.

Если брать сервер отдельно, то имеем следующую ситуацию.

На нашем сервере нет интеграционных тестов.

Тесты API теоретически можно написать, поскольку клиент и сервер общаются по протоколу protobuf. Это значит, что есть описание протокола, можно брать клиента и отправлять запросы.

Но пока мы держим эту идею про запас.

А что насчет клиента? Там дела обстоят несколько трагичнее.

Здесь нет ни модульных, ни компонентных тестов.

Итак, мы оказываемся на вершине пирамиды — нам остается только протестировать наше приложение через UI. Большая часть нашей игры выглядит так: много кнопок, диалогов, всплывающих окон, еще диалогов, еще кнопок.

Почти все элементы интерфейса живут на Canvas.

QA без рутины: как мы автоматизировали регрессионное тестирование

Вот как выглядят разные экраны в Hustle Castle В качестве базового инструмента мы взяли решение с открытым исходным кодом.

АльтЮнитиТестер это драйвер, который обеспечивает:

  1. Поиск объектов с помощью x-path;
  2. Управление сценой;
  3. Имитация способов ввода (касание, прокрутка, перетаскивание и т. д.);
  4. Вызов методов и получение свойств игровых объектов;
  5. Протокол связи через веб-сокет, позволяющий добавлять множество других команд.


QA без рутины: как мы автоматизировали регрессионное тестирование

; В итоге мы взяли Java, Allure, TestNG, решили использовать паттерн Page-Object и начали писать тесты.

Поначалу получилось очень круто и круто.

Мы написали около 10-15 базовых тестов, которые просто ходили по интерфейсу и что-то делали.

Однако быстро стало ясно, что наша кодовая база содержит ряд проблем, которые будут становиться все более и более проблематичными по мере роста проекта.

Первое было связано с селекторы .

На снимке экрана ниже показан пример того, как мы использовали Page-Object. Поля класса были селекторами, а методы содержали вызовы драйвера и дополнительную логику.



QA без рутины: как мы автоматизировали регрессионное тестирование

Проблема заключалась не только в том, что это выглядело массивно, но и в том, что все наши классы были доступны API AltUnity. И если разработчики что-то изменят в новой версии, нам будет мучительно больно обновляться.

Другая проблема заключалась в ответственность Page-Objects .

Во-первых, внутри Page-Object мы напрямую подтянули драйвер (привет, API!).

Во-вторых, объекты могут выполнять сложную логику.

В-третьих, наши Page-Objects знали о других Page-Objects — то есть сами перемещались по объектам.



QA без рутины: как мы автоматизировали регрессионное тестирование

Наши объекты страниц выглядели примерно так Другая проблема заключалась в внедрение зависимости .

Когда занятий было мало, все было хорошо.

Но поскольку тесты усложнялись, приходилось подключать кучу зависимостей, а также держать в голове, какие именно есть.



QA без рутины: как мы автоматизировали регрессионное тестирование

Вот как выглядят зависимости типичного теста: Большое количество зависимостей вызывает ненужные трудности: например, если в компанию придет новый человек и попробует написать автотест, ему нужно будет изучить все многообразие API, составить мысленную карту, какие классы у нас есть и как они связаны между собой и прилагают много усилий, чтобы погрузиться в процесс.



QA без рутины: как мы автоматизировали регрессионное тестирование

Сами тесты выглядели очень запутанными и трудными для понимания.

И последняя проблема, с которой мы столкнулись, это дублирование кода .

Например, на рисунке выше есть метод OpenShopAndBuyRoom, который является приватным для этого тестового класса, поэтому мы не можем использовать его где-либо еще.

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



Время остановиться и подумать

Использование AltUnityTester и шаблона Page-Object очень похоже на автоматизацию разработки веб-приложений.

Наши коллеги там используют Selenium WebDriver. А если мы возьмем концепции из сети и перенесем их в нашу предметную область, то получим:

  1. UnityDriver — взаимодействие с игрой.

  2. Unity-Object — это структурный шаблон для описания диалогов, экранов и сцен.

    Мы используем их только для описания структуры, а вся логика обрабатывается по шагам.

  3. Unity-Element — кнопки, картинки, диалоги, текст и так далее.

    Вообще все, что есть на сцене в Unity, — это UnityElement.

Мы просмотрели исходные коды WebDriver и фреймворка HTML Elements и смогли адаптировать код к нашим потребностям.

Мы также использовали шаблон «Шаги», чтобы отделить логику тестирования от объектов UnityObject. В результате мы получили фреймворк, с помощью которого мы можем:

  1. Разделите сущности на отдельные классы (Button, Label, AbstractDialog и т. д.).

  2. Установите x-путь элементов пользовательского интерфейса с помощью аннотаций @FindBy, а также введите новые аннотации и расширения.

  3. Создавайте отдельные блоки элементов и повторно используйте их в разных диалогах, осуществляя поиск объектов в контексте другого объекта.

  4. Создайте представления компонентов в Unity на тестовой стороне (поскольку объект может иметь несколько компонентов).

  5. Используя шаги, напишите тесты с точки зрения бизнес-логики игры («Открыть магазин», «Купить товар» и так далее).

  6. Код AltUnity находится глубоко в ядре, а драйвер скрыт за интерфейсом.

Немного о шагах — они связывают наши тесты с Unity Objects. Unity Objects позволяют щелкнуть по элементу или передать какие-то данные из игры, а вся логика заключена в шагах.

Это дает нам возможность писать тесты с точки зрения бизнес-процесса.

Например, «На локации — открыть казарму», «В казарме — улучшить казарму», «Взять отряд — переместить его в казарму».

А уже под капотом есть перетаскивание, клики и все остальное.

Вторая особенность шагов заключается в том, что их можно использовать повторно в будущем.

И не только в рамках функциональных тестов.

Например, недавно необходимо было реализовать запуск одного сценария на множестве разных состояний игрока.

Создали новый проект, подключили библиотеку с шагами, несколько строк кода для запуска скрипта — задача выполнена.

Итак, ниже находится объект Unity. Помните, как выглядели наши селекторы? Они были ужасно уродливы.

Теперь мы просто используем аннотации, в которых указываем, как искать нужный элемент и всё.



QA без рутины: как мы автоматизировали регрессионное тестирование

Пример типизированного элемента Вот так выглядит описание практически любого диалога в нашем проекте.

При этом шаги имеют доступ к кнопкам с возможностью нажимать на них, спискам повторяющихся объектов, а также шаги могут получать информацию из всего диалога (сколько у нас золота, какие слоты открыты или закрыты и так далее).

).

Инициализацией полей класса занимается загрузчик элементов Unity — он получает определенный класс и драйвер.

По некоторой логике мы создаем прокси-элементы для каждого поля в классе.

И таким образом мы можем просто написать «Нажать кнопку», хотя на самом деле система сначала найдет эту кнопку, информация об этом вернется обратно, и только после этого будет отправлена команда «Нажать».

Ниже вы можете видеть, что у нас есть шаги для диалогового окна квеста.

И эти шаги описаны в терминах самой игры.



QA без рутины: как мы автоматизировали регрессионное тестирование

Пример теста Вот так выглядят все тесты.

Мы используем только одну инъекцию самих шагов.

На основе него мы пишем в терминах бизнес-логики то, что хотим сделать.

В итоге все выглядит вполне аккуратно.



Планы на будущее

Наши главные планы — провести еще больше тестов.

Все эти усилия были направлены на расширение нашей кодовой базы удобным, простым и понятным способом.

Но впереди нас ждет проблема — многопоточность.

На данный момент тесты выполняются в одном потоке для одного экземпляра игры.

Все работает хорошо, но это занимает много времени.

Чтобы справиться с этим, мы можем создать несколько экземпляров на нашем удаленном сервере.

Или можем собрать ферму устройств и подключиться к ним.

Но некоторые наши функции являются «глобальными» и могут мешать прохождению тестов.

Например, если «Портал для фермерства» открыт, то он открыт для всех.

А при открытии или закрытии «Портала» возникают уведомления, которые могут появиться в интерфейсе параллельно работающего теста, и тап произойдет случайно по уведомлению, а не по нужному элементу.

Следующее, что мы хотели бы реализовать — это back-to-back тесты: это когда вы берете две версии приложения, запускаете один и тот же скрипт и делаете скриншоты в определенный момент. А потом сравниваешь.

Таким образом вы сможете проверить, работает ли у вас что-то, появилась ли функция раньше времени и так далее.




На данный момент мы расширяем охват функционала, у нас есть дым-сет как минимум с одним тестом на любой аспект игры, а также мы начали обучать коллег написанию тестов.

Фреймворк для автоматизации тестирования — это тот же продукт. Он должен быть простым, понятным и легко расширяемым.

При его проектировании не следует забывать о закономерностях и принципах разработки программного обеспечения, а также пренебрегать рефакторингом.

В противном случае спасение себя от регрессии станет вашей головной болью при сопровождении вас.

Иногда стоит сделать шаг назад, чтобы завтра сделать три шага вперед. Теги: #Разработка игр #gamedev #qa #java #unity #Тестирование игр #автоматизация контроля качества

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.