通过 Game Loop 测试,您可以为您的游戏引擎编写本机测试,然后在您选择的设备上的测试实验室中运行它们。这样,您就不必担心为不同的 UI 或测试框架编写代码。游戏循环测试模拟真实玩家的动作,当您在测试实验室中运行它时,它提供了一种快速且可扩展的方法来验证您的游戏是否为您的用户提供良好的性能。
此页面向您展示如何运行游戏循环测试,然后在 Firebase 控制台的测试实验室页面中查看和管理您的测试结果。您还可以使用可选功能进一步自定义测试,例如编写自定义测试结果或提前结束测试。
什么是游戏循环测试?
循环是您对游戏应用程序进行的完整或部分测试。您可以在模拟器或测试实验室中的一组设备上本地运行游戏循环测试。游戏循环测试可用于:
以最终用户玩游戏的方式运行您的游戏。你可以编写用户输入的脚本,让用户空闲,或者用 AI 代替用户(例如,如果你在赛车游戏中实现了 AI,你可以让 AI 司机负责用户的输入) .
以最高质量设置运行您的游戏,以了解哪些设备可以支持它。
运行技术测试,例如编译多个着色器、执行它们并检查输出是否符合预期。
第 1 步:注册测试实验室的自定义 URL 方案
首先,您必须在您的应用中注册 Firebase 测试实验室的自定义 URL 方案:
在 Xcode 中,选择一个项目目标。
单击信息选项卡,然后添加新的URL 类型。
在URL Schemes字段中,输入
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
}
目标-C
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary <UIApplicationOpenURLOptionsKey, id> *)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).
}
}
}
第 3 步:创建并运行测试
注册测试实验室的自定义 URL 架构后,您可以在Firebase 控制台或使用gcloud beta CLI运行测试。如果您还没有为您的应用程序生成一个 IPA 文件(稍后您需要找到它)。
在 Firebase 控制台中运行测试
如果您还没有,请打开Firebase 控制台并创建一个项目。
在 Firebase 控制台的测试实验室页面上,单击运行您的第一个测试 > 运行 iOS 游戏循环。
在上传应用部分,点击浏览,然后选择您应用的 IPA 文件(如果您还没有,请为您的应用生成一个 IPA 文件)。
可选:如果您想一次运行多个循环(又名场景)或选择要运行的特定循环,请在场景字段中输入循环编号。
例如,当您输入“1-3、5”时,Test Lab 会运行循环 1、2、3 和 5。默认情况下(如果您未在Scenarios字段中输入任何内容),Test Lab 只会运行循环 1。
在Devices部分,选择您要在其上测试您的应用程序的一台或多台物理设备,然后单击Start Tests 。
使用 gcloud beta CLI 运行测试
如果您还没有,请配置您的本地 gcloud SDK 环境,然后确保安装gcloud beta 组件。
运行
gcloud beta firebase test ios run
命令并使用以下标志配置运行:
游戏循环测试的标志 | |
---|---|
--type | 必需:指定要运行的 iOS 测试类型。您可以输入测试类型 |
--app | 必需:您应用的 IPA 文件的绝对路径(Google Cloud Storage 或文件系统)。此标志仅在运行游戏循环测试时有效。 |
--scenario-numbers | 您想要在您的应用程序中运行的循环(又名场景)。您可以输入一个循环、一个列表或多个循环或一系列循环。默认循环为 1。 例如, |
--device-model | 您要在其上运行测试的物理设备(找出您可以使用的可用设备)。 |
--timeout | 您希望测试运行的最长持续时间。您可以输入一个整数来表示持续时间(以秒为单位),或者输入一个整数和枚举以将持续时间表示为更长的时间单位。 例如:
|
例如,以下命令运行游戏循环测试,在 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)
}
目标-C
- (void)finishLoop {
UIApplication *app = [UIApplication sharedApplication];
[app openURL:[NSURL URLWithString:@"firebase-game-loop-complete://"]
options:@{}
completionHandler:^(BOOL success) {}];
}
您的游戏循环测试终止当前循环并执行下一个循环。当没有更多循环要运行时,测试结束。
编写自定义测试结果
您可以配置游戏循环测试以将自定义测试结果写入设备的文件系统。这样,当测试开始运行时,测试实验室将结果文件存储在测试设备(您必须自己创建)上的GameLoopsResults
目录中。测试结束时,测试实验室将所有文件从GameLoopResults
目录移动到项目的存储桶中。设置测试时请记住以下几点:
无论文件类型、大小或数量如何,都会上传所有结果文件。
直到测试中的所有循环都运行完毕后,测试实验室才会处理您的测试结果,因此如果您的测试包含多个写入输出的循环,请确保将它们附加到唯一的结果文件或为每个循环创建一个结果文件。这样,您可以避免覆盖前一个循环的结果。
要设置测试以编写自定义测试结果:
在您应用的
Documents
目录中,创建一个名为GameLoopResults
的目录。从您应用程序代码的任何位置(例如,您的应用程序委托)添加以下内容:
迅速
/// 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]; } }