Catch up on highlights from Firebase at Google I/O 2023. Learn more

開始使用遊戲循環測試

當遊戲應用程序構建在不同的 UI 框架上時,很難自動化遊戲測試。 Game Loop 測試允許您將本機測試與測試實驗室集成,並在您選擇的設備上輕鬆運行它們。遊戲循環測試通過您的遊戲應用程序運行您的測試,同時模擬真實玩家的動作。本指南向您展示如何運行遊戲循環測試,然後在 Firebase 控制台中查看和管理您的測試結果。

根據您的遊戲引擎,您可以使用單個或多個循環實施測試。循環是您對遊戲應用程序進行的完整或部分測試。遊戲循環可用於:

  • 以最終用戶玩遊戲的方式運行您的遊戲關卡。您可以編寫用戶輸入的腳本,讓用戶閒置,或者在您的遊戲中有意義時用 AI 替換用戶(例如,假設您有一個賽車遊戲應用程序並且已經實現了 AI。您可以輕鬆讓 AI 驅動程序負責用戶的輸入)。
  • 以最高質量設置運行您的遊戲,看看設備是否支持它。
  • 運行技術測試(編譯多個著色器,執行它們,檢查輸出是否符合預期等)。

您可以在單個測試設備、一組測試設備或測試實驗室上運行遊戲循環測試。但是,我們不建議在虛擬設備上運行遊戲循環測試,因為它們的圖形幀速率低於物理設備。

在你開始之前

要實施測試,您必須首先為遊戲循環測試配置您的應用。

  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>
    

    這允許測試實驗室通過以特定意圖觸發遊戲來啟動您的遊戲。

  2. 在您的代碼中(我們建議在onCreate方法聲明中)添加以下內容:

    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
    }

    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
    }

    這允許您的活動檢查啟動它的意圖。如果您願意,您也可以稍後添加此代碼(例如,在最初加載您的遊戲引擎之後)。

  3. 推薦:在測試結束時,添加:

    Kotlin+KTX

    yourActivity.finish()

    Java

    yourActivity.finish();

    這會在遊戲循環測試完成時關閉您的應用程序。該測試依賴於您應用的 UI 框架來啟動下一個循環,關閉您的應用會告訴它測試已完成。

創建並運行遊戲循環測試

為遊戲循環測試配置應用程序後,您可以立即創建測試並在遊戲應用程序中運行它。您可以選擇使用Firebase 控制台gcloud 命令行界面 (CLI)在測試實驗室中運行測試,或者使用測試循環管理器在本地設備上運行測試。

在本地設備上運行

Test Lab 的Test Loop Manager是一個開源應用程序,可幫助您集成 Game Loop 測試並在本地設備上運行它們。它還允許您的質量保證團隊在他們的設備上運行相同的遊戲循環。

要使用測試循環管理器在本地設備上運行測試:

  1. 在手機或平板電腦上下載測試循環管理器並通過運行安裝它:
    adb install testloopmanager.apk
  2. 在您的設備上,打開手機或平板電腦上的Test Loop Apps應用程序。該應用程序會在您的設備上顯示可以與遊戲循環一起運行的應用程序列表。如果您在此處沒有看到您的遊戲應用程序,請確保您的意圖過濾器與開始之前部分第一步中描述的過濾器相匹配。
  3. 選擇您的遊戲應用程序,然後選擇您要運行的循環次數。注意:在這一步,您可以選擇運行循環的子集而不是只運行一個循環。有關一次運行多個循環的更多信息,請參閱可選功能。
  4. 單擊運行測試。您的測試立即開始運行。

在測試實驗室中運行

您可以使用Firebase 控制台gcloud CLI 在測試實驗室中運行遊戲循環測試。在開始之前,如果您還沒有,請打開Firebase 控制台並創建一個項目。

使用 Firebase 控制台

  1. 在 Firebase 控制台中,單擊左側面板中的測試實驗室
  2. 單擊“運行您的第一個測試” (如果您的項目之前已運行過測試,則單擊“運行測試”)。
  3. 選擇Game Loop作為測試類型,然後單擊Continue
  4. 單擊瀏覽,然後瀏覽到您的應用程序的.apk文件。注意:在這一步,您可以選擇運行循環的子集而不是只運行一個循環。有關一次運行多個循環的更多信息,請參閱可選功能。
  5. 單擊繼續
  6. 選擇用於測試您的應用程序的物理設備。
  7. 單擊開始測試

有關開始使用 Firebase 控制台的更多信息,請參閱使用 Firebase 控制台開始測試。

使用 gcloud 命令行 (CLI)

  1. 如果您還沒有,請下載並安裝Google Cloud SDK。

  2. 使用您的 Google 帳戶登錄到 gcloud CLI:

    gcloud auth login

  3. 在 gcloud 中設置您的 Firebase 項目,其中PROJECT_ID是您的 Firebase 項目的 ID:

    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 的更多信息,請參閱從 gcloud 命令行開始測試。

可選功能

Test Lab 提供了多種可選功能,可讓您進一步自定義測試,包括編寫輸出數據的能力、對多個遊戲循環的支持以及相關循環的標籤。

寫入輸出數據

您的遊戲循環測試可以將輸出寫入launchIntent.getData()方法中指定的文件。運行測試後,您可以在 Firebase 控制台的測試實驗室部分訪問此輸出數據(請參閱遊戲循環測試輸出文件示例)。

測試實驗室遵循共享文件中描述的在應用程序之間共享文件的最佳實踐。在您的活動的onCreate()方法中,您的意圖所在的位置,您可以通過運行以下代碼來檢查您的數據輸出文件:

Kotlin+KTX

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

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

輸出文件示例

您可以使用輸出數據文件(格式如下例)在 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 關崩潰,您可以直接啟動該遊戲循環來重現崩潰並測試錯誤修復。

要使您的應用一次運行多個循環:

  • 如果您正在使用測試循環管理器運行測試:

    1. 將以下行添加到應用程序的清單中的<application>元素內:

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

      此啟動意圖包含目標循環作為整數參數。在android:value字段中,您可以指定 1 到 1024 之間的一個整數(單次測試允許的最大循環次數)。請注意,循環是從 1 開始索引的,而不是 0。

    2. 在 Test Loop Manager 應用程序中,會出現一個選擇屏幕,您可以在其中選擇要運行的循環。如果選擇多個循環,每個循環將在前一個循環完成後按順序啟動。

  • 如果您使用 Firebase 控制台運行測試,請在Scenarios字段中輸入一個列表或一系列循環編號。

  • 如果您使用 gcloud CLI 運行測試,請使用--scenario-numbers標誌指定循環編號列表。例如, --scenario-numbers=1,3,5運行循環 1、3 和 5。

  • 如果您正在編寫 C++ 並希望更改循環的行為,請將以下額外內容傳遞給您的本機 C++ 代碼:

    Kotlin+KTX

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

    Java

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

    您現在可以根據生成的int值更改循環的行為。

標記遊戲循環

當您使用一個或多個場景標籤標記您的遊戲循環時,您和您的 QA 團隊可以輕鬆啟動一組相關的遊戲循環(例如,“所有兼容性遊戲循環”)並在單個矩陣中測試它們。您可以創建自己的標籤或使用測試實驗室提供的預定義標籤:

  • com.google.test.loops.player_experience :用於在玩遊戲時重現真實用戶體驗的循環。使用這些循環進行測試的目的是找出真實用戶在玩遊戲時會遇到的問題。
  • com.google.test.loops.gpu_compatibility :用於測試 GPU 相關問題的循環。使用這些循環進行測試的目的是執行可能無法在生產中正常運行的 GPU 代碼,以暴露硬件和驅動程序的問題。
  • com.google.test.loops.compatibility :用於測試各種兼容性問題的循環,包括 I/O 問題和 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"LABEL_NAME應用於循環 1、3、4 和 5。

    2. 在 Test Loop Manager 應用程序中,在標籤字段中輸入一個或多個標籤。

  • 如果您使用 Firebase 控制台運行測試,請在標籤字段中輸入一個或多個標籤。

  • 如果您使用 gcloud CLI 運行測試,請使用--scenario-labels標誌(例如--scenario-labels=performance,gpu )指定一個或多個場景標籤。

應用許可支持

測試實驗室支持使用 Google Play 提供的應用許可服務的應用。要在使用測試實驗室測試您的應用程序時成功檢查許可,您必須將您的應用程序發佈到 Play 商店的生產渠道。要使用測試實驗室在 alpha 或 beta 渠道中測試您的應用程序,請在將您的應用程序上傳到測試實驗室之前刪除許可檢查。

已知的問題

測試實驗室中的遊戲循環測試存在以下已知問題:

  • 一些崩潰不支持回溯。例如,某些發布版本可能會使用prctl(PR_SET_DUMPABLE, 0)抑制debuggerd進程的輸出。要了解更多信息,請參閱debuggerd
  • 由於文件權限錯誤,目前不支持 API 級別 19。