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

ゲームループテストを実行する

ゲームアプリがさまざまなUIフレームワークで構築されている場合、ゲームテストを自動化するのは難しい場合があります。ゲームループテストを使用すると、ネイティブテストをTest Labと統合して、選択したデバイスで簡単に実行できます。このガイドでは、Firebase TestLabを使用して実行するゲームループテストを準備する方法について説明します。

ゲームループテストについて

ゲームループテストとは何ですか?

ゲームループテストは、実際のプレーヤーのアクションをシミュレートして、ゲームがユーザーにとって高速かつスケーラブルな方法で適切に実行されることを確認します。ループは、ゲームアプリでのテストの完全または部分的な実行です。ゲームループテストは、シミュレーターまたはテストラボの一連のデバイスでローカルに実行できます。ゲームループテストは、次の目的で使用できます。

  • エンドユーザーがプレイするようにゲームを実行します。ユーザーの入力をスクリプト化するか、ユーザーをアイドル状態にするか、ユーザーをAIに置き換えることができます(たとえば、カーレースゲームにAIを実装した場合、ユーザーの入力をAIドライバーに任せることができます) 。
  • 最高品質の設定でゲームを実行して、どのデバイスがそれをサポートできるかを調べます。
  • 複数のシェーダーをコンパイルして実行し、出力が期待どおりであることを確認するなどの技術テストを実行します。

ステップ1 :TestLabのカスタムURLスキームを登録する

  1. Xcodeで、プロジェクトターゲットを選択します。

  2. [情報]タブをクリックしてから、新しいURLタイプを追加します。

  3. [ URLスキーム]フィールドに、 firebase-game-loopと入力します。 <dict>タグ内の任意の場所でプロジェクトのInfo.plist構成ファイルに追加することにより、カスタム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>
    

これで、TestLabを使用してテストを実行するようにアプリが構成されました。

ステップ2 :オプションでアプリを構成します

複数のループを実行する

テストで複数のループ(別名シナリオ)を実行する場合は、起動時にアプリで実行するループを指定する必要があります。

アプリデリゲートで、 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).
        }
    }
}

テストを早期に終了する

デフォルトでは、すべてのループが実行された場合でも、ゲームループテストは5分のタイムアウトに達するまで実行を続けます。タイムアウトに達すると、テストは終了し、保留中のループをキャンセルします。アプリのAppDelegateでTestLabのカスタムURLスキームfirebase 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) {}];
}

ゲームループテストは現在のループを終了し、次のループを実行します。実行するループがなくなると、テストは終了します。

カスタムテスト結果を書く

カスタムテスト結果をデバイスのファイルシステムに書き込むようにゲームループテストを構成できます。このように、テストの実行が開始されると、Test Labは結果ファイルをテストデバイスのGameLoopsResultsディレクトリに保存します(自分で作成する必要があります)。テストが終了すると、TestLabはすべてのファイルをGameLoopResultsディレクトリからプロジェクトのバケットに移動します。テストを設定するときは、次の点に注意してください。

  • すべての結果ファイルは、ファイルタイプ、サイズ、または数量に関係なくアップロードされます。

  • Test Labは、テスト内のすべてのループの実行が終了するまでテスト結果を処理しません。したがって、出力を書き込む複数のループがテストに含まれている場合は、それらを一意の結果ファイルに追加するか、ループごとに結果ファイルを作成してください。このようにして、前のループからの結果を上書きすることを回避できます。

カスタムテスト結果を書き込むようにテストを設定するには:

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

ステップ3 :アップロード用にアプリをパッケージ化します

最後に、アプリのIPAファイルを生成します(後で見つける必要があります)。

  1. Xcodeで、ターゲットアプリのプロビジョニングプロファイルを選択します。

  2. 表示されるドロップダウンメニューから、[製品]> [アーカイブ]をクリックします。最新のアーカイブを選択し、[アプリの配布]をクリックします。

  3. 表示されるウィンドウで、[開発]> [次へ]をクリックします。

  4. オプション:ビルドを高速化するには、[ビットコードから再ビルド]オプションの選択を解除し、[次へ]をクリックします。 Test Labでは、テストを実行するためにアプリを間引いたり再構築したりする必要がないため、このオプションを安全に無効にできます。

  5. [エクスポート]をクリックし、アプリのIPAファイルをダウンロードするディレクトリを入力します。

ステップ4 :ローカルでテストを実行する

Test Labで実行する前に、テストをローカルで実行して動作を確認できます。ローカルでテストするには、ゲームアプリをシミュレーターにロードして、次のコマンドを実行します。

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
  • シミュレータのUDIDは、 instruments -s devicesコマンドを実行することで見つけることができます。

  • 実行中のシミュレータが1つしかない場合は、 SIMULATOR_UDIDの代わりに特別な文字列"booted"を入力します。

テストに複数のループが含まれている場合は、ループ番号をscenarioフラグに渡すことで、実行するループを指定できます。テストをローカルで実行する場合、一度に実行できるループは1つだけであることに注意してください。たとえば、ループ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

次のステップ

FirebaseコンソールまたはgcloudCLIを使用してテストを実行します。