開始使用遊戲迴圈測試

如果遊戲應用程式是以不同的 UI 架構建構,可能難以自動化遊戲測試。遊戲迴圈測試可讓您將原生測試與 Test Lab 整合,並在所選裝置上輕鬆執行。遊戲迴圈測試會透過遊戲應用程式執行測試,同時模擬實際玩家的動作。本指南說明如何執行遊戲迴圈測試,以及如何在 Firebase 控制台查看及管理測試結果。

什麼是遊戲迴圈測試?

由於遊戲應用程式會跨不同的 UI 架構和引擎 (例如 Unity、Unreal 或 OpenGL/Vulkan C++ 程式碼) 轉譯,因此標準自動化工具無法檢查 UI 元素或與其互動。遊戲迴圈測試可讓您將原生引擎測試與 Test Lab 整合,方法是使用包含特定情境編號的意圖啟動遊戲。這個情境編號會提示應用程式直接在遊戲引擎中執行預先編寫的邏輯、AI 模擬或效能檢查。

啟動後,Test Lab 不會再與遊戲 UI 互動。Test Lab 會做為測試傳輸和環境:啟動特定情境、監控當機和逾時情形,並在應用程式完成迴圈執行時收集任何自訂結果記錄。

遊戲迴圈與檢測設備測試的差異

  • 檢測設備測試 (例如 Espresso 或 UI Automator) 仰賴外部架構,從應用程式外部驅動 UI 互動、點擊按鈕,並在 Android 檢視區塊階層中斷言應用程式狀態。
  • 遊戲迴圈測試會將測試邏輯委派給應用程式。應用程式會執行自己的內部測試迴圈或模擬,不需外部 UI 互動,而 Test Lab 會觸發情境並收集測試輸出內容。

範例

假設您想確認遊戲在各種實體裝置上,是否能維持每秒至少 60 個影格。您可以在遊戲程式碼中實作情境 1,載入視覺效果最複雜的關卡,並讓 AI 玩家或自動化指令碼玩兩分鐘。

當 Test Lab 觸發情境 1 時,遊戲會開始 AI 試玩、監控影格轉譯時間和記憶體用量、將這些指標串流至自訂輸出記錄檔 (logFile),並在完成時呼叫 finish()。Test Lab 接著會擷取記錄檔,並在 Cloud Storage 和 Firebase 控制台中提供給您。

用途

視遊戲引擎而定,您可以實作單一或多個迴圈的測試。迴圈是指在遊戲應用程式上完整或部分執行測試。 遊戲迴圈可用於:

  • 像使用者一樣玩遊戲,您可以編寫使用者輸入內容的指令碼、讓使用者處於閒置狀態,或在遊戲中以 AI 取代使用者 (例如,如果您有賽車遊戲應用程式,且已導入 AI,則可讓 AI 駕駛負責使用者輸入內容)。
  • 以最高畫質設定執行遊戲,確認裝置是否支援。
  • 執行技術測試 (編譯多個著色器、執行著色器、檢查輸出內容是否符合預期等)。

您可以在單一測試裝置、一組測試裝置或 Test Lab 上執行遊戲迴圈測試。不過,我們不建議在虛擬裝置上執行遊戲迴圈測試,因為虛擬裝置的圖像影格率低於實體裝置。

事前準備

如要執行測試,您必須先設定應用程式,才能進行遊戲迴圈測試。

  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 方法宣告中),新增下列內容:

    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
    }

    這樣一來,活動就能檢查啟動該活動的意圖。您也可以稍後再新增這段程式碼 (例如在遊戲引擎初次載入後)。

  3. 建議:在測試結尾處新增:

    Kotlin

    yourActivity.finish()

    Java

    yourActivity.finish();

    這樣一來,系統就會在遊戲迴圈測試完成時關閉應用程式。測試會依據應用程式的 UI 架構啟動下一個迴圈,關閉應用程式則代表測試已完成。

建立及執行遊戲迴圈測試

為應用程式設定遊戲迴圈測試後,您可以立即建立測試,並在遊戲應用程式中執行。您可以選擇使用 Firebase 控制台或 gcloud 指令列介面 (CLI) 在 Test Lab 中執行測試,也可以使用測試迴圈管理程式在本機裝置上執行測試。

在本機裝置上執行

Test Lab 的測試迴圈管理程式是一款開放原始碼應用程式,可協助您整合遊戲迴圈測試,並在本機裝置上執行。此外,品質查驗團隊也能在裝置上執行相同的遊戲迴圈。

如要使用測試迴圈管理程式在本機裝置上執行測試,請按照下列步驟操作:

  1. 在手機或平板電腦上下載測試迴圈管理程式,然後執行下列指令進行安裝:
    adb install testloopmanager.apk
  2. 在裝置上,開啟手機或平板電腦上的「Test Loop Apps」應用程式。應用程式會顯示裝置上可透過遊戲迴圈執行的應用程式清單。如果這裡未顯示您的遊戲應用程式,請確認意圖篩選器與「事前準備」一節第一個步驟所述的篩選器相符。
  3. 選取遊戲應用程式,然後選取要執行的迴圈數量。注意:在這個步驟中,您可以選擇執行部分迴圈,而非只執行一個迴圈。如要進一步瞭解如何同時執行多個迴圈,請參閱「選用功能」。
  4. 按一下「執行測試」。測試會立即開始執行。

在 Test Lab 中執行

您可以使用 Firebase 控制台或 gcloud CLI,在 Test Lab 中執行遊戲迴圈測試。開始之前,請先開啟 Firebase 控制台並建立專案 (如果尚未建立)。

使用 Firebase 控制台

  1. 在 Firebase 控制台中,按一下左側面板中的Test Lab。
  2. 按一下「Run Your First Test」 (如果專案先前已執行過測試,則按一下「Run a Test」)。
  3. 選取「遊戲迴圈」做為測試類型,然後按一下「繼續」。
  4. 按一下「Browse」,然後瀏覽至應用程式的 .apk 檔案。注意:在這個步驟中,您可以選擇執行部分迴圈,而非只執行一個迴圈。如要進一步瞭解如何同時執行多個迴圈,請參閱「選用功能」。
  5. 按一下「繼續」。
  6. 選取要用來測試應用程式的實體裝置。
  7. 按一下「Start Tests」。

如要進一步瞭解如何開始使用 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 提供多項選用功能,可讓您進一步自訂測試,包括寫入輸出資料、支援多個遊戲迴圈,以及為相關迴圈加上標籤。

寫入輸出資料

Test Lab 啟動遊戲時,會指定指向測試裝置上本機結果檔案的網址,可使用 launchIntent.getData() 存取。在測試執行期間,遊戲可以直接將測試結果、成效指標和記錄 (logFile) 寫入這個位置。

您可以將任何內容寫入 logFile,例如純文字、CSV 資料、影格轉譯時間或自訂診斷報告。您編寫的內容沒有任何限制或格式要求;測試完成後,系統會擷取檔案,並與其他測試構件一起上傳至 Cloud Storage bucket。

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)。從應用程式寫入檔案時,只要欄位名稱不與 name 或 start_timestamp 等結構定義欄位衝突,您就可以在輸出內容中新增任何有效的 JSON 屬性。
  • 輸出檔案的位置:測試完成後,原始輸出檔案會儲存在專案的 Cloud Storage (GCS) 結果 bucket 中,位於測試執行構件目錄內,可供下載。您也可以在 Firebase 控制台的「Test Lab」頁面,查看及檢查剖析後的輸出內容。

以下是結構化 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. 在測試迴圈管理程式應用程式中,會顯示選取畫面,讓您選取要執行的迴圈。如果選取多個迴圈,每個迴圈會在前一個迴圈完成後依序啟動。

  • 如果您使用 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:用於測試 GPU 相關問題的 For 迴圈。使用這些迴圈進行測試的目標,是執行可能無法在正式環境中正常執行的 GPU 程式碼,以找出硬體和驅動程式的問題。
  • com.google.test.loops.compatibility:用於測試各種相容性問題的 for 迴圈,包括 I/O 問題和 OpenSSL 問題。
  • com.google.test.loops.performance:用於測試裝置 效能的 for 迴圈。舉例來說,遊戲可能會以最複雜的圖形設定執行,藉此瞭解新裝置的行為。

如要讓應用程式執行具有相同標籤的迴圈,請按照下列步驟操作:

  • 如果使用測試迴圈管理程式執行測試:

    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. 在測試迴圈管理程式應用程式中,於「Labels」(標籤) 欄位輸入一或多個標籤。

  • 如果您使用 Firebase 控制台執行測試,請在「Labels」(標籤) 欄位中輸入一或多個標籤。

  • 如果使用 gcloud CLI 執行測試,請透過 --scenario-labels 旗標指定一或多個情境標籤 (例如 --scenario-labels=performance,gpu)。

應用程式授權支援

Test Lab 支援使用 Google Play 提供的應用程式授權服務。使用 Test Lab 測試應用程式時,如要成功檢查授權,您必須將應用程式發布到 Play 商店的正式版管道。如要使用 Test Lab 在 Alpha 或 Beta 版測試應用程式,請先移除授權檢查,再將應用程式上傳到 Test Lab。

已知問題

Test Lab中的遊戲迴圈測試有下列已知問題:

  • 部分當機事件不支援回溯追蹤。舉例來說,某些發布子版本可能會使用 prctl(PR_SET_DUMPABLE, 0) 抑制 debuggerd 程序的輸出內容。詳情請參閱 debuggerd。
  • 由於檔案權限錯誤,目前不支援 API 級別 19。