開始使用遊戲迴圈測試

如果遊戲應用程式是採用不同的 UI 架構建構而成,自動化遊戲測試可能會很困難。透過遊戲迴圈測試,您可以將原生測試與 Test Lab 整合,並在選取的裝置上輕鬆執行測試。遊戲迴圈測試會透過遊戲應用程式執行測試,同時模擬真實玩家的動作。本指南說明如何執行遊戲迴圈測試,然後在 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 架構啟動下一個迴圈,而關閉應用程式則會告知測試已完成。

建立及執行遊戲迴圈測試

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

在本機裝置上執行

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

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

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

Test Lab 中執行

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

使用 Firebase 控制台

  1. Firebase 控制台中,按一下左側面板中的 Test Lab
  2. 按一下「Run Your First Test」(執行第一項測試) (如果專案先前已執行過測試,則為「Run a Test」)
  3. 選取「遊戲迴圈」做為測試類型,然後按一下「繼續」
  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

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

輸出檔案範例

您可以使用輸出資料檔案 (格式如下方範例所示),在 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 級別當機,您就能直接啟動該遊戲迴圈來重現當機情形,並測試修正錯誤。

如要讓應用程式同時執行多個迴圈,請按照下列步驟操作:

  • 如果您使用 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 控制台執行測試,請在「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 值變更迴圈的行為。

標記遊戲迴圈

為遊戲迴圈加上一或多個情境標籤後,您和 QA 團隊就能輕鬆啟動一組相關的遊戲迴圈 (例如「所有相容性遊戲迴圈」,並在單一矩陣中測試。你可以自行建立標籤,也可以使用 Test Lab 提供的預先定義標籤:

  • 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 應用程式的「Labels」欄位中,輸入一或多個標籤。

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

  • 如果使用 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。