Автоматизировать тестирование игр может быть сложно, поскольку игровые приложения создаются на основе разных фреймворков пользовательского интерфейса. Тесты игрового цикла позволяют интегрировать нативные тесты с Test Lab и легко запускать их на выбранных устройствах. Тест игрового цикла запускается в игровом приложении и имитирует действия реального игрока. В этом руководстве рассказывается, как запустить тестирование игрового цикла, а затем посмотреть результаты и управлять ими в консоли Firebase.
Что такое тест с игровым циклом?
Поскольку мобильные игры отображаются в разных фреймворках и движках пользовательского интерфейса, таких как Unity, Unreal или OpenGL/Vulkan C++, стандартные инструменты автоматизации не могут проверять элементы пользовательского интерфейса или взаимодействовать с ними. Тестирование игрового цикла позволяет интегрировать тесты нативного движка с Test Lab, запуская игру с намерением, содержащим определенный номер сценария. Этот номер сценария заставляет ваше приложение запускать предварительно написанную логику, симуляции ИИ или проверки производительности непосредственно в вашем игровом движке.
После запуска Test Lab не взаимодействует с интерфейсом игры. Вместо этого Test Lab выступает в качестве тестовой среды: запускает определенный сценарий, отслеживает сбои и тайм-ауты и собирает журналы результатов, когда приложение завершает выполнение цикла.
Чем игровые циклы отличаются от инструментальных тестов
- Инструментальные тесты (например, Espresso или UI Automator) используют внешние фреймворки для управления взаимодействием с интерфейсом, нажатия кнопок и подтверждения состояния приложения в иерархии View за пределами приложения.
- Тесты игрового цикла делегируют логику тестирования вашему приложению. Оно запускает собственный внутренний цикл тестирования или симуляцию без внешнего взаимодействия с пользовательским интерфейсом, а Test Lab запускает ваш сценарий и собирает результаты теста.
Примеры
Предположим, вы хотите убедиться, что ваша игра поддерживает частоту кадров не менее 60 кадров в секунду на различных физических устройствах. Вы можете реализовать сценарий 1 в коде игры, чтобы загрузить самый сложный с визуальной точки зрения уровень и позволить ИИ-игроку или автоматизированному скрипту пройти его за две минуты.
Когда Test Lab запускает сценарий 1, игра начинает прохождение с ИИ, отслеживает время отрисовки кадров и использование памяти, передает эти показатели в пользовательский выходной файл журнала (logFile) и по завершении вызывает finish().
Test Lab сохраняет файл журнала и делает его доступным для вас в Cloud Storage и консоли Firebase.
Примеры использования
В зависимости от игрового движка вы можете реализовать тесты с одним или несколькими циклами. Цикл – это полное или частичное тестирование мобильной игры. Игровые циклы можно использовать, чтобы:
- Пройдите уровень игры так, как это сделал бы конечный пользователь. Вы можете либо запрограммировать ввод пользователя, либо оставить его бездействующим, либо заменить его ИИ, если это имеет смысл в вашей игре (например, если у вас есть мобильная игра про гоночные автомобили и у вас уже реализован ИИ, вы можете поставить водителя ИИ, отвечающего за ввод пользователя).
- Запустите игру с самыми высокими настройками качества, чтобы проверить, поддерживают ли их устройства.
- Выполните технический тест (скомпилируйте несколько шейдеров, запустите их, проверьте, соответствуют ли выходные данные ожидаемым, и т. д.).
Тестирование игрового цикла можно запустить на одном или нескольких устройствах, а также в Test Lab. Однако мы не рекомендуем запускать тесты игрового цикла на виртуальных устройствах, поскольку частота кадров у них ниже, чем у физических устройств.
Подготовка
Чтобы провести тестирование, сначала необходимо настроить приложение для тестов игрового цикла.
Добавьте в манифест приложения новый фильтр интентов для activity:
<activity android:name=".MyActivity"> <intent-filter> <action android:name="com.google.intent.action.TEST_LOOP"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/javascript"/> </intent-filter> <intent-filter> ... (other intent filters here) </intent-filter> </activity>Это позволит Test Lab запускать вашу игру, активируя ее с помощью определенного намерения.
Добавьте в код (рекомендуем сделать это в объявлении метода
onCreate) следующее:Kotlin
val launchIntent = intent if (launchIntent.action == "com.google.intent.action.TEST_LOOP") { val scenario = launchIntent.getIntExtra("scenario", 0) // Code to handle your game loop here }
Java
Intent launchIntent = getIntent(); if(launchIntent.getAction().equals("com.google.intent.action.TEST_LOOP")) { int scenario = launchIntent.getIntExtra("scenario", 0); // Code to handle your game loop here }
Это позволяет вашему действию проверять намерение, которое его запускает. Вы также можете добавить этот код позже, например после первоначальной загрузки игрового движка.
Рекомендуем в конце теста добавить:
Kotlin
yourActivity.finish()
Java
yourActivity.finish();
Это позволит закрыть приложение после завершения тестирования игрового цикла. Для запуска следующего цикла тест использует фреймворк пользовательского интерфейса приложения. Закрытие приложения означает, что тест завершен.
Как создать и запустить тест с игровым циклом
После настройки приложения для тестирования игрового цикла вы можете сразу создать тест и запустить его в мобильной игре. Тест можно запустить в Test Lab с помощью консоли Firebase или интерфейса командной строки gcloud, а также на локальном устройстве с помощью Менеджера тестирования.
Запуск на локальном устройстве
Test LabМенеджер тестирования – это приложение с открытым исходным кодом, которое помогает интегрировать тесты игровых циклов и запускать их на локальных устройствах. Это также позволяет вашей команде по обеспечению качества запускать те же игровые циклы на своих устройствах.
Чтобы запустить тест на локальном устройстве с помощью Менеджера тестирования, выполните следующие действия:
- Скачайте Менеджер тестирования на телефон или планшет и установите его, выполнив следующую команду:
adb install testloopmanager.apk
- Откройте приложение Test Loop Apps на телефоне или планшете. В приложении появится список приложений на вашем устройстве, которые можно запустить с игровыми циклами. Если вы не видите свою мобильную игру, убедитесь, что фильтр интентов соответствует описанному в первом шаге раздела Подготовка.
- Выберите мобильную игру, затем укажите, сколько циклов нужно выполнить. Примечание. На этом этапе вы можете выбрать подмножество циклов, а не только один цикл. Подробнее о том, как запустить несколько циклов одновременно…
- Нажмите Проверить. Тестирование начнется сразу же.
Бег в течение Test Lab
Вы можете запустить тест игрового цикла в Test Lab с помощью консоли Firebase или gcloud CLI. Если вы ещё этого не сделали, откройте консоль Firebase и создайте проект.
Используйте консоль Firebase
- В консоли Firebase на панели слева нажмите Test Lab.
- Нажмите Run Your First Test (Запустить первый тест) или Run a Test (Запустить тест), если вы уже проводили тестирование в этом проекте.
- Выберите тип теста Игровой цикл и нажмите Продолжить.
- Нажмите Обзор и найдите файл
.apkсвоего приложения. Примечание. На этом этапе вы можете выбрать подмножество циклов, а не только один цикл. Подробнее о том, как запускать несколько циклов одновременно, рассказывается в разделе Дополнительные функции. - Нажмите Продолжить.
- Выберите физические устройства, на которых будет тестироваться приложение.
- Нажмите Начать тестирование.
Подробнее о том, Firebase как начать работу с консолью Firebase…
Как использовать интерфейс командной строки gcloud
Если вы ещё этого не сделали, скачайте и установите Google Cloud SDK.
Войдите в gcloud CLI, используя аккаунт Google:
gcloud auth loginУкажите проект Firebase в gcloud, где
PROJECT_ID– это идентификатор проекта Firebase:gcloud config set project PROJECT_ID
Запустите первый тест:
gcloud firebase test android run \ --type=game-loop --app=<var>path-to-apk</var> \ --device model=herolte,version=23
Подробнее о том, как начать работу с gcloud CLI…
Дополнительные функции
Test Lab предлагает несколько дополнительных функций, которые позволяют настраивать тесты, в том числе возможность записывать выходные данные, поддержку нескольких игровых циклов и ярлыки для связанных циклов.
Запись выходных данных
При запуске игры Test Lab указывает URL, который ведет к локальному файлу с результатами на тестовом устройстве. Доступ к нему можно получить с помощью launchIntent.getData(). Во время тестирования игра может записывать результаты, показатели эффективности и журналы (logFile) непосредственно в эту папку.
В logFile можно записывать любой контент, например обычный текст, данные CSV, время отрисовки кадров или специальные диагностические отчеты. Ограничений или требований к форматированию контента нет. По завершении тестирования файл будет загружен в сегмент Cloud Storage вместе с другими артефактами.
Test Lab следует рекомендациям по обмену файлами между приложениями, описанным в статье Обмен файлами.
В методе onCreate() своего объекта activity, где находится намерение, вы можете получить и проверить выходной файл данных, выполнив следующий код:
Kotlin
val launchIntent = intent val logFile = launchIntent.data logFile?.let { Log.i(TAG, "Log file ${it.encodedPath}") // ... }
Java
Intent launchIntent = getIntent(); Uri logFile = launchIntent.getData(); if (logFile != null) { Log.i(TAG, "Log file " + logFile.getEncodedPath()); // ... }
Если вы хотите записать данные в файл из кода C++ в игровом приложении, то вместо пути к файлу можно передать дескриптор файла:
Kotlin
val launchIntent = intent val logFile = launchIntent.data var fd = -1 logFile?.let { Log.i(TAG, "Log file ${it.encodedPath}") fd = try { contentResolver .openAssetFileDescriptor(logFile, "w")!! .parcelFileDescriptor .fd } catch (e: FileNotFoundException) { e.printStackTrace() -1 } catch (e: NullPointerException) { e.printStackTrace() -1 } } // C++ code invoked here. // native_function(fd);
Java
Intent launchIntent = getIntent(); Uri logFile = launchIntent.getData(); int fd = -1; if (logFile != null) { Log.i(TAG, "Log file " + logFile.getEncodedPath()); try { fd = getContentResolver() .openAssetFileDescriptor(logFile, "w") .getParcelFileDescriptor() .getFd(); } catch (FileNotFoundException e) { e.printStackTrace(); fd = -1; } catch (NullPointerException e) { e.printStackTrace(); fd = -1; } } // C++ code invoked here. // native_function(fd);
C++
#include <unistd.h> JNIEXPORT void JNICALL Java_my_package_name_MyActivity_native_function(JNIEnv *env, jclass type, jint log_file_descriptor) { // The file descriptor needs to be duplicated. int my_file_descriptor = dup(log_file_descriptor); }
Пример выходного файла
Хотя Test Lab не требует определенного формата для logFile, структурирование выходных данных в виде JSON, соответствующего приведенной ниже схеме, позволяет консоли Firebase (https://console.firebase.google.com/project/_/testlab) анализировать и отображать сводные показатели для вашего теста игрового цикла.
Важные детали:
- Кто предоставляет данные. Вы (разработчик теста) отвечаете за расчет и запись всех показателей в этот файл из кода игры. Test Lab не собирает и не генерирует эти элементы данных автоматически.
- Добавление специальных полей. Области, помеченные как
/.../, указывают, где можно добавить произвольные пары "ключ-значение" (например,"rendered_vertices": 12000или"ai_error_count": 0). При записи файла из приложения вы можете добавить в выходные данные любое допустимое свойство JSON, если имена полей не конфликтуют с полями схемы, такими какnameилиstart_timestamp. - Где найти выходной файл. После завершения теста необработанный выходной файл сохраняется в сегменте результатов Cloud Storage (
GCS) вашего проекта в каталоге артефактов тестового запуска. Вы можете скачать этот файл. Вы также можете просматривать и проверять обработанные выходные данные на странице Test Lab в консоли Firebase.
Ниже приведен пример структурированного выходного файла JSON.
{
"name": "test name",
"start_timestamp": 0, // Timestamp of the test start (in us).
Can be absolute or relative
"driver_info": "...",
"frame_stats": [
{
"timestamp": 1200000, // Timestamp at which this section was written
It contains value regarding the period
start_timestamp(0) -> this timestamp (1200000 us)
"avg_frame_time": 15320, // Average time to render a frame in ns
"nb_swap": 52, // Number of frame rendered
"threads": [
{
"name": "physics",
"Avg_time": 8030 // Average time spent in this thread per frame in us
},
{
"name": "AI",
"Avg_time": 2030 // Average time spent in this thread per frame in us
}
],
/.../ // Any custom field you want (vertices display on the screen, nb units …)
},
{
// Next frame data here, same format as above
}
],
"loading_stats": [
{
"name": "assets_level_1",
"total_time": 7850, // in us
/.../
},
{
"name": "victory_screen",
"total_time": 554, // in us
/.../
}
],
/.../, // You can add custom fields here
}
Несколько игровых циклов
В приложении можно запустить несколько игровых циклов. Цикл – это полное прохождение игры от начала до конца. Например, если в игре несколько уровней, можно создать отдельный игровой цикл для каждого из них, а не один цикл, который проходит через все уровни. Например, если приложение дает сбой на 32-м уровне, вы можете запустить соответствующий игровой цикл, чтобы воспроизвести сбой и проверить исправление ошибок.
Чтобы приложение могло запускать несколько циклов одновременно, выполните следующие действия:
Если вы проводите тестирование с помощью Менеджера тестирования:
Добавьте в манифест приложения следующую строку внутри элемента
<application>:<meta-data android:name="com.google.test.loops" android:value="5" />
Этот объект Intent содержит целевой цикл в виде целочисленного параметра. В поле
android:valueможно указать целое число от 1 до 1024 (максимальное количество циклов, разрешенное для одного теста). Обратите внимание, что циклы индексируются начиная с 1, а не с 0.В приложении "Менеджер тестирования" появится экран, на котором можно выбрать нужные циклы. Если вы выберете несколько циклов, они будут запускаться по очереди.
Если вы запускаете тест с помощью консоли Firebase, введите список или диапазон номеров циклов в поле Scenarios (Сценарии).
Если вы запускаете тест с помощью gcloud CLI, укажите список номеров циклов, используя флаг
--scenario-numbers. Например,--scenario-numbers=1,3,5запускает циклы 1, 3 и 5.Если вы пишете на C++ и хотите изменить поведение цикла, передайте в нативный код C++ следующее дополнение:
Kotlin
val launchIntent = intent val scenario = launchIntent.getIntExtra("scenario", 0)
Java
Intent launchIntent = getIntent(); int scenario = launchIntent.getIntExtra("scenario", 0);
Теперь вы можете изменить поведение цикла на основе полученного значения
int.
Как пометить игровые циклы
Если вы добавите к игровым циклам один или несколько ярлыков сценариев, вы и ваша команда контроля качества сможете легко запустить набор связанных игровых циклов (например, "все игровые циклы совместимости") и протестировать их в одной матрице. Вы можете создать собственные ярлыки или использовать стандартные, предлагаемые Test Lab:
com.google.test.loops.player_experience– циклы, которые используются для воспроизведения действий реального пользователя во время игры. Цель тестирования с помощью этих циклов – найти проблемы, с которыми может столкнуться реальный пользователь во время игры.com.google.test.loops.gpu_compatibility: циклы for, используемые для тестирования проблем, связанных с графическим процессором. Цель тестирования с помощью этих циклов – выполнить код графического процессора, который может работать неправильно в рабочей версии, чтобы выявить проблемы с аппаратным обеспечением и драйверами.com.google.test.loops.compatibility– циклы for, используемые для тестирования широкого спектра проблем совместимости, включая проблемы с вводом-выводом и OpenSSL.com.google.test.loops.performance: циклы for, используемые для тестирования производительности устройства. Например, можно запустить игру с самыми сложными настройками графики, чтобы посмотреть, как поведет себя новое устройство.
Чтобы приложение могло выполнять циклы с одним и тем же ярлыком, сделайте следующее:
Если вы проводите тестирование с помощью Менеджера тестирования:
Добавьте в манифест приложения следующую строку метаданных и замените LABEL_NAME на нужный ярлык:
<meta-data android:name="com.google.test.loops.LABEL_NAME" android:value="1,3-5" />
В поле
android:valueможно указать диапазон или набор целых чисел от 1 до 1024 (максимальное количество циклов, разрешенное для одного теста), которые представляют циклы, которые вы хотите пометить. Обратите внимание, что циклы индексируются, начиная с 1, а не с 0. Например,android:value="1,3-5"применяет LABEL_NAME к циклам 1, 3, 4 и 5.В приложении Test Loop Manager введите один или несколько ярлыков в поле Labels (Ярлыки).
Если вы проводите тестирование в консоли Firebase, введите один или несколько ярлыков в поле Ярлыки.
Если вы запускаете тест с помощью gcloud CLI, укажите один или несколько ярлыков сценариев, используя флаг
--scenario-labels(например,--scenario-labels=performance,gpu).
Поддержка лицензирования приложений
Test Lab поддерживает приложения, в которых используется сервис лицензирования приложений от Google Play. Чтобы успешно проверить лицензирование при тестировании приложения с помощью Test Lab, необходимо опубликовать приложение в рабочем канале в Google Play. Чтобы протестировать приложение в альфа- или бета-канале с помощью Test Lab, удалите проверку лицензии перед загрузкой приложения в Test Lab.
Известные проблемы
При тестировании игровых циклов в Test Lab могут возникать следующие проблемы:
- Некоторые сбои не поддерживают обратную трассировку. Например, в некоторых конечных сборках вывод процесса
debuggerdможет подавляться с помощьюprctl(PR_SET_DUMPABLE, 0). Подробнее:debuggerd. - Уровень API 19 сейчас не поддерживается из-за ошибок, связанных с разрешениями для файлов.