Check out what’s new from Firebase at Google I/O 2022. Learn more

開始使用遊戲循環測試

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

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

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

您可以在單個測試設備、一組測試設備或測試實驗室上運行遊戲循環測試。但是,我們不建議在虛擬設備上運行 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>
    

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

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

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

創建並運行遊戲循環測試

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

在本地設備上運行

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

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

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

在測試實驗室運行

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

使用 Firebase 控制台

  1. 在 Firebase 控制台中,單擊左側面板中的測試實驗室
  2. 單擊運行您的第一個測試(如果您的項目之前運行過測試,則單擊運行測試)。
  3. 選擇Game Loop作為測試類型,然後單擊Continue
  4. 單擊Browse ,然後瀏覽到您的應用的.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 命令行開始測試。

可選功能

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

寫入輸出數據

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

測試實驗室遵循共享文件中描述的在應用程序之間共享文件的最佳實踐。在您的意圖所在的活動的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);

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 控制台運行測試,請在“場景”字段中輸入一個列表或循環編號範圍。

  • 如果您使用 gcloud CLI 運行測試,請使用--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 團隊可以輕鬆啟動一組相關的遊戲循環(例如,“所有兼容性遊戲循環”)並在單個矩陣中測試它們。您可以創建自己的標籤或使用測試實驗室提供的預定義標籤:

  • 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 提供的應用許可服務的應用。要在使用 Test Lab 測試您的應用程序時成功檢查許可,您必須將您的應用程序發佈到 Play 商店的生產渠道。要使用測試實驗室在 Alpha 或 Beta 通道中測試您的應用,請在將您的應用上傳到測試實驗室之前刪除許可檢查。

已知的問題

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

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