Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Начните с тестов Game Loop

Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.

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

В зависимости от вашего игрового движка вы можете реализовать тесты с одним или несколькими циклами . Цикл — это полное или частичное выполнение теста в игровом приложении. Игровые циклы можно использовать для:

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

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

Прежде чем вы начнете

Чтобы реализовать тест, вы должны сначала настроить свое приложение для тестов Game Loop.

  1. В манифесте приложения добавьте новый фильтр намерений к своей активности :

    <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 ) добавьте следующее:

    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+KTX

    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
    }

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

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

    Java

    yourActivity.finish();

    Kotlin+KTX

    yourActivity.finish()

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

Создайте и запустите тест Game Loop

После настройки приложения для тестов Game Loop вы можете сразу же создать тест и запустить его в своем игровом приложении. Вы можете запустить тест в Test Lab с помощью консоли Firebase или интерфейса командной строки (CLI) gcloud или на локальном устройстве с помощью Test Loop Manager .

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

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

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

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

Запустить в тестовой лаборатории

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

Используйте консоль Firebase

  1. В консоли Firebase нажмите « Тестовая лаборатория» на левой панели.
  2. Щелкните « Выполнить первый тест» (или «Выполнить тест », если в вашем проекте уже выполнялся тест).
  3. Выберите « Игровой цикл» в качестве типа теста и нажмите « Продолжить ».
  4. Нажмите « Обзор » и перейдите к файлу .apk вашего приложения. Примечание. На этом этапе вы можете выбрать запуск подмножества циклов вместо одного цикла. Дополнительные сведения об одновременном запуске нескольких циклов см. в разделе Дополнительные функции.
  5. Нажмите Продолжить .
  6. Выберите физические устройства, которые будут использоваться для тестирования вашего приложения.
  7. Нажмите «Начать тесты» .

Дополнительные сведения о начале работы с консолью Firebase см. в статье Начало тестирования с помощью консоли Firebase.

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

  1. Если вы еще этого не сделали, загрузите и установите Google Cloud SDK.

  2. Войдите в интерфейс командной строки gcloud, используя свою учетную запись 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 см. в разделе Запуск тестирования из командной строки gcloud.

Дополнительные особенности

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

Запись выходных данных

Ваш тест Game Loop может записывать выходные данные в файл, указанный в launchIntent.getData() . После запуска теста вы можете получить доступ к этим выходным данным в разделе « Тестовая лаборатория » консоли Firebase (см. пример выходного файла теста Game Loop ).

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

Java

Intent launchIntent = getIntent();
Uri logFile = launchIntent.getData();
if (logFile != null) {
    Log.i(TAG, "Log file " + logFile.getEncodedPath());
    // ...
}

Kotlin+KTX

val launchIntent = intent
val logFile = launchIntent.data
logFile?.let {
    Log.i(TAG, "Log file ${it.encodedPath}")
    // ...
}

Если вы хотите писать в файл со стороны C++ вашего игрового приложения, вы можете передать дескриптор файла вместо пути к файлу:

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);

Kotlin+KTX

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);

С++

#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);
}

Пример выходного файла

Вы можете использовать файлы выходных данных (отформатированные как в примере ниже) для отображения результатов тестов игрового цикла в разделе « Тестовая лаборатория » консоли Firebase. Области, показанные как /.../ , могут содержать любые настраиваемые поля, которые вам нужны, если они не конфликтуют с именами других полей, используемых в этом файле:

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

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

  • Если вы запускаете тест с помощью Test Loop Manager:

    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, укажите список номеров циклов, используя флаг --scenario-numbers . Например, --scenario-numbers=1,3,5 запускает циклы 1, 3 и 5.

  • Если вы пишете на C++ и хотите изменить поведение своего цикла, передайте в собственный код на C++ следующее дополнение:

    Java

    Intent launchIntent = getIntent();
    int scenario = launchIntent.getIntExtra("scenario", 0);

    Kotlin+KTX

    val launchIntent = intent
    val scenario = launchIntent.getIntExtra("scenario", 0)

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

Обозначьте игровые циклы

Когда вы помечаете свои игровые циклы одним или несколькими ярлыками сценариев, вы и ваша команда QA можете легко запустить набор связанных игровых циклов (например, «все игровые циклы совместимости») и протестировать их в одной матрице. Вы можете создавать свои собственные метки или использовать предустановленные метки, предлагаемые Test Lab:

  • com.google.test.loops.player_experience : для циклов, используемых для воспроизведения реального опыта пользователя во время игры. Цель тестирования с помощью этих циклов — найти проблемы, с которыми реальный пользователь столкнется во время игры.
  • com.google.test.loops.gpu_compatibility : для циклов, используемых для тестирования проблем, связанных с графическим процессором. Целью тестирования с помощью этих циклов является выполнение кода графического процессора, который может неправильно работать в производственной среде, для выявления проблем с оборудованием и драйверами.
  • com.google.test.loops.compatibility : для циклов, используемых для тестирования широкого спектра проблем совместимости, включая проблемы с вводом-выводом и проблемы с OpenSSL.
  • com.google.test.loops.performance : для циклов, используемых для проверки производительности устройства. Например, игра может запускаться с самыми сложными настройками графики, чтобы увидеть, как ведет себя новое устройство.

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

  • Если вы запускаете тест с помощью Test Loop Manager:

    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" применяет LABEL_NAME к циклам 1, 3, 4 и 5.

    2. В приложении Test Loop Manager введите одну или несколько меток в поле Labels .

  • Если вы запускаете тест с помощью консоли Firebase, введите один или несколько ярлыков в поле « Ярлыки ».

  • Если вы выполняете тест с помощью интерфейса командной строки gcloud, укажите одну или несколько меток сценария с помощью --scenario-labels (например, --scenario-labels=performance,gpu ).

Поддержка лицензирования приложений

Test Lab поддерживает приложения, использующие службу лицензирования приложений , предлагаемую Google Play. Чтобы успешно проверить лицензию при тестировании приложения с помощью Test Lab, вы должны опубликовать свое приложение в производственном канале в магазине Play. Чтобы протестировать приложение в альфа- или бета-канале с помощью Test Lab, удалите проверку лицензии перед загрузкой приложения в Test Lab.

Известные вопросы

Тесты Game Loop в Test Lab имеют следующие известные проблемы:

  • Некоторые сбои не поддерживают обратную трассировку. Например, некоторые сборки выпуска могут подавлять вывод процесса debuggerd с помощью prctl(PR_SET_DUMPABLE, 0) . Чтобы узнать больше, см. debuggerd .
  • Уровень API 19 в настоящее время не поддерживается из-за ошибок прав доступа к файлам.