iOS 遊戲循環測試入門

透過遊戲循環測試,您可以編寫遊戲引擎本機測試,然後在您選擇的裝置上的測試實驗室中執行它們。這樣,您就不必擔心為不同的 UI 或測試框架編寫程式碼。遊戲循環測試模擬真實玩家的操作,當您在測試實驗室上運行它時,它提供了一種快速且可擴展的方法來驗證您的遊戲是否對使用者表現良好。

本頁面向您展示如何執行遊戲循環測試,然後在 Firebase 控制台的測試實驗室頁面中檢視和管理測試結果。您還可以使用選用功能進一步自訂測試,例如編寫自訂測試結果提前結束測試

什麼是遊戲循環測試?

循環是對遊戲應用程式進行完整或部分測試。您可以在模擬器上或測試實驗室中的一組裝置上本地執行遊戲循環測試。遊戲循環測試可用於:

  • 以最終用戶玩遊戲的方式運行您的遊戲。你可以將使用者的輸入編寫成腳本,讓使用者閒置,或用AI取代使用者(例如,如果你在賽車遊戲中實現了AI,你可以讓一個AI驅動程式負責使用者的輸入) 。

  • 以最高品質設定運行遊戲,看看哪些設備可以支援它。

  • 執行技術測試,例如編譯多個著色器、執行它們並檢查輸出是否符合預期。

第 1 步:註冊測試實驗室的自訂 URL 方案

首先,您必須在應用程式中註冊 Firebase 測試實驗室的自訂 URL 方案:

  1. 在 Xcode 中,選擇專案目標。

  2. 按一下「資訊」選項卡,然後新增新的URL 類型

  3. URL 方案欄位中,輸入firebase-game-loop 。您也可以透過將自訂 URL 方案新增至專案的Info.plist設定檔<dict>標記內的任意位置來註冊自訂 URL 方案:

    <key>CFBundleURLTypes</key>
     <array>
         <dict>
             <key>CFBundleURLName</key>
             <string></string>
             <key>CFBundleTypeRole</key>
             <string>Editor</string>
             <key>CFBundleURLSchemes</key>
             <array>
                 <string>firebase-game-loop</string>
             </array>
         </dict>
     </array>
    

您的應用程式現已配置為使用測試實驗室執行測試。

步驟 2(可選):設定您的應用程式以執行多個循環

如果您的應用程式註冊了多個自訂 URL 方案,並且您計劃在測試中執行多個循環(也稱為場景),則必須指定要在啟動時在應用程式中執行哪些循環。

在您的應用程式委託中,重寫application(_:open:options:)方法:

迅速

func application(_app: UIApplication,
                 open url: URL
                 options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!
    if components.scheme == "firebase-game-loop" {
        // ...Enter Game Loop Test logic to override application(_:open:options:).
    }
    return true
}

Objective-C

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary &lt;UIApplicationOpenURLOptionsKey, id&gt; *)options {
  if ([url.scheme isEqualToString:(@"firebase-game-loop")]) {
      // ...Enter Game Loop Test logic to override application(_:open:options:).
  }
}

當您在測試中執行多個循環時,當前循環將作為參數傳遞給用於啟動應用程式的 URL。您也可以透過解析用於取得自訂 URL 方案的URLComponents物件來取得目前循環編號:

迅速

if components.scheme == "firebase-game-loop" {
    // Iterate over all parameters and find the one with the key "scenario".
    let scenarioNum = Int(components.queryItems!.first(where: { $0.name == "scenario" })!.value!)!
    // ...Write logic specific to the current loop (scenarioNum).
}

Objective-C

if ([url.scheme isEqualToString:(@"firebase-game-loop")]) {
    // Launch the app as part of a game loop.
    NSURLComponents *components = [NSURLComponents componentsWithURL:url
                                             resolvingAgainstBaseURL:YES];
    for (NSURLQueryItem *item in [components queryItems]) {
        if ([item.name isEqualToString:@"scenario"]) {
            NSInteger scenarioNum = [item.value integerValue];
            // ...Write logic specific to the current loop (scenarioNum).
        }
    }
}

第 3 步:建立並執行測試

註冊測試實驗室的自訂 URL 方案後,您可以在Firebase 控制台或使用gcloud beta CLI執行測試。如果您還沒有為您的應用程式產生 IPA 檔案(您稍後需要找到它)。

在 Firebase 控制台中執行測試

  1. 如果您還沒有這樣做,請開啟Firebase 控制台並建立專案。

  2. 在 Firebase 控制台的「測試實驗室」頁面上,按一下「執行您的第一個測試」>「執行 iOS 遊戲循環」

  3. 「上傳應用程式」部分中,按一下「瀏覽」 ,然後選擇應用程式的 IPA 檔案(如果尚未為您的應用程式產生 IPA 檔案)。

  4. 可選:如果您想要一次執行多個循環(也稱為場景)或選擇要執行的特定循環,請在場景欄位中輸入循環編號。

    例如,當您輸入「1-3, 5」時,測試實驗室將執行循環 1、2、3 和 5。預設(如果您未在「場景」欄位中輸​​入任何內容),測試實驗室僅運行循環1。

  5. 「設備」部分中,選擇要在其上測試應用程式的一台或多台實體設備,然後按一下「開始測試」

使用 gcloud beta CLI 運行測試

  1. 如果您尚未設定本機 gcloud SDK 環境,請確保安裝gcloud beta 元件

  2. 運行gcloud beta firebase test ios run命令並使用以下標誌來設定運行:

遊戲循環測試的標誌
--type

必要:指定要執行的 iOS 測試的類型。您可以輸入測試類型xctest (預設)或game-loop

--app

必要:應用程式的 IPA 檔案的絕對路徑(Google Cloud Storage 或檔案系統)。此標誌僅在執行遊戲循環測試時有效。

--scenario-numbers

您想要在應用程式中運行的循環(也稱為場景)。您可以輸入一個循環、一個或多個循環清單或一系列循環。預設循環為 1。

例如, --scenario-numbers=1-3,5運行循環 1、2、3 和 5。

--device-model

您想要執行測試的實體設備(找出您可以使用哪些可用設備)。

--timeout

您希望測試運行的最長持續時間。您可以輸入一個整數來表示以秒為單位的持續時間,或輸入整數和枚舉來表示較長時間單位的持續時間。

例如:

  • --timeout=200強制測試在運行時間達到 200 秒時終止。
  • --timeout=1h強制測試在運行長達一小時時終止。

例如,以下指令執行遊戲循環測試,在 iPhone 8 Plus 上執行循環 1、4、6、7 和 8:

gcloud beta firebase test ios run
 --type game-loop --app path/to/my/App.ipa --scenario-numbers 1,4,6-8
 --device-model=iphone8plus

有關 gcloud CLI 的更多信息,請參閱參考文檔

在本地運行測試

要在本地運行測試,請在模擬器中載入遊戲應用程式並運行:

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
  • 您可以透過執行instruments -s devices指令找到模擬器的UDID。

  • 如果只執行一個模擬器,請輸入特殊字串"booted"來取代SIMULATOR_UDID

如果您的測試包含多個循環,您可以透過將循環編號傳遞給scenario標誌來指定要執行的循環。請注意,在本地運行測試時一次只能運行一個循環。例如,如果要執行循環 1、2 和 5,則必須為每個循環執行單獨的命令:

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=1
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=2
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=5

提前結束測試

預設情況下,即使所有循環都已執行,遊戲循環測試也會繼續運行,直到達到五分鐘超時。當達到超時時,測試結束並取消任何掛起的循環。您可以透過在應用程式的 AppDelegate 中呼叫測試實驗室的自訂 URL 方案firebase-game-loop-complete來加快測試速度或提前結束測試。例如:

迅速

/// End the loop by calling our custom url scheme.
func finishLoop() {
    let url = URL(string: "firebase-game-loop-complete://")!
    UIApplication.shared.open(url)
}

Objective-C

- (void)finishLoop {
  UIApplication *app = [UIApplication sharedApplication];
  [app openURL:[NSURL URLWithString:@"firebase-game-loop-complete://"]
      options:@{}
completionHandler:^(BOOL success) {}];
}

您的遊戲循環測試將終止當前循環並執行下一個循環。當不再有循環可運行時,測試結束。

編寫自訂測試結果

您可以設定遊戲循環測試以將自訂測試結果寫入裝置的檔案系統。這樣,當測試開始運行時,測試實驗室會將結果檔案儲存在測試裝置上的GameLoopsResults目錄中(您必須自行建立)。測試結束後,測試實驗室會將所有檔案從GameLoopResults目錄移至專案的儲存桶中。設定測試時請記住以下幾點:

  • 無論文件類型、大小或數量如何,所有結果文件都會上傳。

  • 在測試中的所有循環完成運行之前,測試實驗室不會處理您的測試結果,因此,如果您的測試包含多個寫入輸出的循環,請確保將它們附加到唯一的結果檔案或為每個循環建立一個結果檔。這樣,您可以避免覆蓋先前循環的結果。

要設定測試以寫入自訂測試結果:

  1. 在應用程式的Documents目錄中,建立一個名為GameLoopResults的目錄。

  2. 從應用程式程式碼中的任何位置(例如,您的應用程式委託)添加以下內容:

    迅速

    /// Write to a results file.
    func writeResults() {
      let text = "Greetings from game loops!"
      let fileName = "results.txt"
      let fileManager = FileManager.default
      do {
    
      let docs = try fileManager.url(for: .documentDirectory,
                                     in: .userDomainMask,
                                     appropriateFor: nil,
                                     create: true)
      let resultsDir = docs.appendingPathComponent("GameLoopResults")
      try fileManager.createDirectory(
          at: resultsDir,
          withIntermediateDirectories: true,
          attributes: nil)
      let fileURL = resultsDir.appendingPathComponent(fileName)
      try text.write(to: fileURL, atomically: false, encoding: .utf8)
      } catch {
        // ...Handle error writing to file.
      }
    }
    

    Objective-C

    /// Write to a results file.
    - (void)writeResults:(NSString *)message {
        // Locate and create the results directory (if it doesn't exist already).
        NSFileManager *manager = [NSFileManager defaultManager];
        NSURL* url = [[manager URLsForDirectory:NSDocumentDirectory
                                      inDomains:NSUserDomainMask] lastObject];
        NSURL* resultsDir = [url URLByAppendingPathComponent:@"GameLoopResults"
                                                 isDirectory:YES];
        [manager createDirectoryAtURL:resultsDir
          withIntermediateDirectories:NO
                           attributes:nil
                                error:nil];
    
        // Write the result message to a text file.
        NSURL* resultFile = [resultsDir URLByAppendingPathComponent:@"result.txt"];
        if ([manager fileExistsAtPath:[resultFile path]]) {
            // Append to the existing file
            NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:resultFile
                                                                     error:nil];
            [handle seekToEndOfFile];
            [handle writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
            [handle closeFile];
        } else {
            // Create and write to the file.
            [message writeToURL:resultFile
                     atomically:NO
                       encoding:NSUTF8StringEncoding error:nil];
        }
    }