開始使用遊戲迴圈測試

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

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

  • 以使用者遊玩遊戲的方式執行遊戲關卡。您可以為使用者輸入內容編寫指令碼、讓使用者處於閒置狀態,或是在遊戲中以 AI 取代使用者 (如果這樣做合理的話)。舉例來說,假設您有一個賽車遊戲應用程式,且已實作 AI,您可以輕鬆將 AI 驅動程式設為負責處理使用者輸入內容。
  • 以最高畫質設定執行遊戲,看看裝置是否支援。
  • 執行技術測試 (編譯多個著色器、執行著色器、檢查輸出內容是否符合預期等)。

您可以在單一測試裝置、一組測試裝置,或 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 方法宣告內) 加入下列內容:

    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 架構來啟動下一個迴圈,而關閉應用程式會告知測試已完成。

建立及執行遊戲迴圈測試

設定應用程式以進行 Game Loop 測試後,您可以立即建立測試並在遊戲應用程式中執行。您可以選擇在 Test Lab 中使用 Firebase 主控台gcloud 指令列介面 (CLI),或是在本機裝置上使用 Test Loop Manager 執行測試。

在本機裝置上執行

Test LabTest Loop Manager 是開放原始碼應用程式,可協助您整合遊戲迴圈測試,並在本機裝置上執行這些測試。這也讓品質管控團隊可以在裝置上執行相同的遊戲迴圈。

如要使用 Test Loop Manager 在本機裝置上執行測試,請按照下列步驟操作:

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

Test Lab 中執行

您可以使用 Firebase 主控台gcloud CLITest Lab 中執行 Game Loop 測試。開始前,如果您尚未開啟 Firebase 主控台,請先建立專案。

使用 Firebase 主控台

  1. Firebase 控制台中,按一下左側面板中的 Test Lab
  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 主控台的 Test Lab 專區中存取這項輸出資料 (請參閱遊戲迴圈測試輸出檔案範例)。

Test Lab 遵循「共用檔案」一文中所述的應用程式間共用檔案最佳做法。在意圖所在的活動 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 主控台的 Test Lab 部分顯示遊戲迴圈測試結果。顯示為 /.../ 的區域可以包含您需要的任何自訂欄位,只要這些欄位名稱不會與此檔案中使用的其他欄位名稱衝突即可:

{
  "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++ 程式碼,並想變更迴圈的行為,請將下列額外項目傳遞至原生 C++ 程式碼:

    Kotlin+KTX

    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: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. 在 Test Loop Manager 應用程式中,在「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。