Как начать тестирование с игровым циклом

Автоматизировать тестирование игр бывает сложно, поскольку игровые приложения создаются на разных платформах. Тесты игрового цикла позволяют интегрировать собственные тесты с Test Lab и легко запускать их на выбранных устройствах. Тестирование игрового цикла запускает ваше приложение и имитирует действия реального игрока. В этом руководстве рассказывается, как запустить тестирование игрового цикла, а затем посмотреть и обработать результаты в консоли Firebase.

Что такое тест с игровым циклом?

Поскольку игровые приложения отрисовываются с помощью разных фреймворков и движков, таких как Unity, Unreal или код OpenGL/Vulkan C++, стандартные инструменты автоматизации не могут проверять элементы интерфейса и взаимодействовать с ними. Тестирование игрового цикла позволяет интегрировать тесты вашего собственного движка с Test Lab, запуская игру с намерением, содержащим номер определенного сценария. Этот номер сценария запускает в приложении предварительно заданную логику, симуляции на основе ИИ или проверки производительности непосредственно в игровом движке.

После запуска Test Lab больше не взаимодействует с интерфейсом игры. Вместо этого Test Lab выступает в качестве тестовой среды и транспорта: он запускает определенный сценарий, отслеживает сбои и тайм-ауты и собирает любые пользовательские журналы результатов, когда приложение завершает выполнение цикла.

Чем игровые циклы отличаются от инструментальных тестов

  • Инструментальные тесты (например, Espresso или UI Automator) используют внешние фреймворки для управления взаимодействием с интерфейсом, нажатиями кнопок и утверждениями о состоянии приложения в иерархии представлений Android извне приложения.
  • Тестирование игрового цикла позволяет передать логику тестирования приложению. Приложение запускает собственный внутренний цикл тестирования или моделирование без внешнего взаимодействия с интерфейсом, а Test Lab запускает сценарий и собирает результаты тестирования.

Примеры

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

Когда Test Lab запускает сценарий 1, ваша игра начинает воспроизведение с помощью ИИ, отслеживает время отрисовки кадров и использование памяти, передает эти показатели в специальный файл журнала (logFile) и вызывает finish() по завершении. Test Lab захватывает файл журнала и делает его доступным в Cloud Storage и консоли Firebase.

Примеры использования

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

  • Пройдите уровень игры так, как это сделал бы обычный пользователь. Вы можете либо запрограммировать ввод пользователя, либо позволить пользователю бездействовать, либо заменить пользователя ИИ, если это имеет смысл в вашей игре (например, если у вас есть мобильная игра про гоночные автомобили и в ней уже реализован ИИ, вы можете поручить ИИ-водителю ввод пользователя).
  • Запустите игру с максимальными настройками качества, чтобы проверить, поддерживают ли устройства их.
  • Проведите технический тест (скомпилируйте несколько шейдеров, выполните их, проверьте, соответствует ли результат ожидаемому, и т. д.).

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

Подготовка

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

  1. В манифесте приложения добавьте новый фильтр интентов в 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 запускать игру, активируя ее с помощью определенного намерения.

  2. Добавьте в код (рекомендуем в объявление метода 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
    }

    Это позволяет объекту activity проверить намерение, которое его запускает. Вы также можете добавить этот код позже, например после первоначальной загрузки игрового движка.

  3. Рекомендуем добавить в конце теста:

    Kotlin

    yourActivity.finish()

    Java

    yourActivity.finish();

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

Как создать и запустить тест с игровым циклом

После того как вы настроите мобильную игру для тестирования игрового цикла, вы сможете сразу же создать тест и запустить его в мобильной игре. Вы можете запустить тест в Test Lab, используя консоль Firebase или интерфейс командной строки gcloud, или на локальном устройстве с помощью Менеджера тестирования.

Запуск на локальном устройстве

Test LabTest Loop Manager – это приложение с открытым исходным кодом, которое помогает интегрировать тесты игровых циклов и запускать их на локальных устройствах. Кроме того, это позволит команде контроля качества запускать одни и те же игровые циклы на своих устройствах.

Чтобы запустить тест на локальном устройстве с помощью Test Loop Manager, выполните следующие действия:

  1. Скачайте Test Loop Manager на телефон или планшет и установите его, выполнив следующую команду:
    adb install testloopmanager.apk
  2. На телефоне или планшете откройте приложение Test Loop Apps. В приложении появится список приложений на устройстве, которые можно запустить с помощью игровых циклов. Если вы не видите здесь свою мобильную игру, убедитесь, что фильтр интентов соответствует описанному в первом шаге подготовительного раздела.
  3. Выберите мобильную игру, затем укажите количество циклов. Примечание. На этом этапе можно выбрать не один, а несколько циклов. Подробнее о том, как запустить несколько циклов одновременно…
  4. Нажмите Запустить тест. Тестирование начнется сразу.

Бег на Test Lab

Вы можете запустить тест игрового цикла в Test Lab, используя консоль Firebase или gcloud CLI. Прежде чем начать, откройте консоль Firebase и создайте проект, если вы ещё этого не сделали.

Как использовать консоль Firebase

  1. В консоли Firebase на панели слева нажмите Test Lab.
  2. Нажмите Run Your First Test (Запустить первый тест) или Run a Test (Запустить тест), если в вашем проекте уже проводились тесты.
  3. Выберите тип тестирования игровой цикл и нажмите Продолжить.
  4. Нажмите Обзор и найдите файл .apk приложения. Примечание. На этом этапе можно выбрать не один, а несколько циклов. Подробнее о том, как запустить несколько лупов одновременно…
  5. Нажмите Продолжить.
  6. Выберите физические устройства, на которых вы хотите протестировать приложение.
  7. Нажмите Начать тестирование.

Подробнее о том, Firebase как начать тестирование с помощью консоли Firebase…

Используйте командную строку gcloud

  1. Если вы ещё не сделали этого, скачайте и установите Google Cloud SDK.

  2. Войдите в gcloud CLI, используя аккаунт Google:

    gcloud auth login

  3. Укажите проект Firebase в gcloud, где PROJECT_ID – это идентификатор вашего проекта Firebase:

    gcloud config set project PROJECT_ID
    
  4. Как провести первое тестирование

    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() своей операции, где находится ваше намерение, вы можете получить и проверить выходной файл данных, выполнив следующий код:

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-м уровне, вы можете сразу запустить этот игровой цикл, чтобы воспроизвести сбой и проверить исправления ошибок.

Чтобы в приложении можно было запускать несколько циклов одновременно:

  • Если вы проводите тестирование с помощью Менеджера тестовых циклов:

    1. Добавьте в манифест приложения следующую строку в элемент <application>:

      <meta-data
        android:name="com.google.test.loops"
        android:value="5" />

      Этот запрос на запуск содержит целевой цикл в виде целочисленного параметра. В поле android:value можно указать целое число от 1 до 1024 (максимальное количество циклов для одного теста). Обратите внимание, что циклы индексируются начиная с 1, а не с 0.

    2. В приложении Test Loop Manager появится экран выбора, на котором можно указать, какие циклы нужно запустить. Если вы выберете несколько циклов, каждый из них будет запускаться по очереди после завершения предыдущего.

  • Если вы проводите тестирование с помощью консоли Firebase, введите список или диапазон номеров циклов в поле Сценарии.

  • Если вы проводите тестирование с помощью gcloud CLI, укажите список номеров циклов, используя флаг --scenario-numbers. Например, --scenario-numbers=1,3,5 выполняет циклы 1, 3 и 5.

  • Если вы пишете код на 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, используемые для тестирования проблем, связанных с GPU. Цель тестирования с помощью этих циклов – выполнить код GPU, который может работать неправильно в производственной среде, чтобы выявить проблемы с оборудованием и драйверами.
  • com.google.test.loops.compatibility: для циклов, используемых для тестирования широкого спектра проблем совместимости, включая проблемы ввода-вывода и OpenSSL.
  • com.google.test.loops.performance: циклы, используемые для тестирования производительности устройства. Например, в игре могут быть заданы самые сложные настройки графики, чтобы проверить, как работает новое устройство.

Чтобы приложение могло запускать циклы с одним и тем же ярлыком:

  • Если вы проводите тестирование с помощью Менеджера тестовых циклов:

    1. В манифест приложения добавьте следующую строку метаданных и замените 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" применяется к циклам 1, 3, 4 и 5.LABEL_NAME

    2. В приложении Test Loop Manager введите один или несколько ярлыков в поле Ярлыки.

  • Если вы проводите тестирование с помощью консоли 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 в настоящее время не поддерживается из-за ошибок с разрешениями для файлов.