Google 致力于为黑人社区推动种族平等。查看具体举措

运行游戏循环测试

当游戏应用程序构建在不同的 UI 框架上时,游戏测试自动化可能很困难。游戏循环测试允许您将本机测试与测试实验室集成,并在您选择的设备上轻松运行它们。本指南介绍了如何使用 Firebase 测试实验室准备要运行的游戏循环测试。

关于游戏循环测试

什么是游戏循环测试?

游戏循环测试模拟真实玩家的动作,以快速且可扩展的方式验证您的游戏是否对用户表现良好。循环是对游戏应用程序测试的全部或部分运行。您可以在模拟器或测试实验室中的一组设备上本地运行游戏循环测试。游戏循环测试可用于:

  • 像最终用户一样运行您的游戏。您可以编写用户输入的脚本,让用户空闲,或者用 AI 替换用户(例如,如果您在赛车游戏中实现了 AI,则可以让 AI 驱动程序负责用户的输入) .
  • 以最高质量设置运行您的游戏,以找出哪些设备可以支持它。
  • 运行技术测试,例如编译多个着色器、执行它们并检查输出是否符合预期。

第 1 步:注册测试实验室的自定义 URL 方案

  1. 在 Xcode 中,选择一个项目目标。

  2. 单击信息选项卡,然后添加新的URL 类型

  3. URL Schemes字段中,输入firebase-game-loop 。您还可以通过将自定义 URL 方案添加到项目的Info.plist配置文件中<dict>标记内的任何位置来注册它:

    <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 步:可选地配置您的应用程序

运行多个循环

如果您计划在测试中运行多个循环(也称为场景),则必须指定要在启动时在应用程序中运行的循环。

在您的应用委托中,覆盖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
}

目标-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).
}

目标-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).
        }
    }
}

提前结束测试

默认情况下,游戏循环测试会继续运行,直到达到五分钟的超时,即使所有循环都已执行。达到超时后,测试结束并取消任何挂起的循环。您可以通过在应用的 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)
}

目标-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.
      }
    }
    

    目标-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. 可选:要获得更快的构建,请取消选择Rebuild from Bitcode选项,然后单击Next 。测试实验室不需要精简或重建您的应用程序来运行测试,因此您可以安全地禁用此选项。

  5. 单击“导出” ,然后输入要在其中下载应用程序的 IPA 文件的目录。

第 4 步:在本地运行您的测试

在使用测试实验室运行之前,您可以在本地运行测试以检查其行为。要在本地进行测试,请在模拟器中加载您的游戏应用程序并运行:

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

下一步

使用Firebase 控制台gcloud CLI运行您的测试。