Автоматизация тестирования игр может быть сложной задачей, особенно если игровые приложения созданы на основе различных фреймворков пользовательского интерфейса. Тесты Game Loop позволяют интегрировать ваши нативные тесты с Test Lab и легко запускать их на выбранных вами устройствах. В этом руководстве описано, как подготовить тест Game Loop для запуска с помощью Firebase Test Lab .
О тестах игрового цикла
Что такое тест игрового цикла?
Тест игрового цикла имитирует действия реального игрока, чтобы проверить, насколько хорошо ваша игра работает для пользователей, обеспечивая быструю и масштабируемую производительность. Цикл представляет собой полное или частичное выполнение теста в вашем игровом приложении. Вы можете запустить тест игрового цикла локально на симуляторе или на наборе устройств в Test Lab . Тесты игрового цикла могут использоваться для:
- Проведите игру так, как в неё играл бы конечный пользователь. Вы можете либо запрограммировать ввод данных пользователем, либо оставить пользователя в режиме ожидания, либо заменить пользователя искусственным интеллектом (например, если вы внедрили ИИ в гоночную игру, вы можете назначить водителя с ИИ для управления вводом данных пользователем).
- Запустите игру с максимальными настройками качества, чтобы узнать, какие устройства её поддерживают.
- Проведите техническое тестирование, например, скомпилируйте несколько шейдеров, выполните их и убедитесь, что результат соответствует ожиданиям.
Шаг 1 : Зарегистрируйте пользовательскую схему URL-адресов Test Lab
В Xcode выберите целевой объект проекта.
Перейдите на вкладку «Информация» , затем добавьте новый тип URL-адреса .
В поле «Схемы URL» введите
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>
Теперь ваше приложение настроено для запуска тестов с помощью Test Lab .
Шаг 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 <UIApplicationOpenURLOptionsKey, id> *)options {
if ([url.scheme isEqualToString:(@"firebase-game-loop")]) {
// ...Enter Game Loop Test logic to override application(_:open:options:).
}
}
При выполнении нескольких циклов в тесте текущий цикл передается в качестве параметра URL-адресу, используемому для запуска приложения. Номер текущего цикла также можно получить, проанализировав объект URLComponents используемый для получения пользовательской схемы URL:
Быстрый
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).
}
}
}
Завершите тест раньше времени.
По умолчанию тест игрового цикла продолжает выполнение до истечения пятиминутного таймаута, даже если все циклы выполнены. По истечении таймаута тест завершается и отменяет все ожидающие циклы. Вы можете ускорить выполнение теста или завершить его раньше, вызвав пользовательскую схему URL-адресов Test Lab firebase-game-loop-complete в AppDelegate вашего приложения. Например:
Быстрый
/// 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) {}];
}
Тест игрового цикла завершает текущий цикл и переходит к следующему. Когда циклы для выполнения заканчиваются, тест завершается.
Напишите пользовательские результаты тестирования
You can configure your Game Loop test to write custom test results to your device's file system. This way, when the test starts running, Test Lab stores the result files in a GameLoopsResults directory on your testing device (which you must create yourself). When the test ends, Test Lab moves all files from the GameLoopResults directory to your project's bucket. Keep the following in mind when setting up your test:
Все файлы с результатами загружаются независимо от типа, размера или количества файлов.
Test Lab не обрабатывает результаты ваших тестов до тех пор, пока не завершатся все циклы в вашем тесте. Поэтому, если ваш тест включает несколько циклов, записывающих результаты, убедитесь, что вы добавляете их в отдельный файл результатов или создаете отдельный файл результатов для каждого цикла. Таким образом, вы сможете избежать перезаписи результатов предыдущего цикла.
Чтобы настроить тест для записи пользовательских результатов:
В папке
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. } }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 : Подпишите ваше приложение
Убедитесь, что все артефакты в приложении подписаны. Например, это можно сделать через Xcode, указав параметры подписи, такие как профиль подготовки и идентификатор. Для получения дополнительной информации см.: Подпись Apple.
Шаг 4 : Упакуйте ваше приложение для загрузки.
Создайте IPA-файл для вашего приложения (его вам нужно будет найти позже).
В появившемся выпадающем меню выберите Продукт > Архив . Выберите самый последний архив, затем нажмите Распространить приложение .
В появившемся окне нажмите «Разработка» > «Далее» .
Нажмите «Экспорт» , затем укажите папку, в которую вы хотите загрузить IPA-файл вашего приложения.
Шаг 5 : Проверка подписи приложения
- Проверьте подпись приложения, распаковав файл .ipa и запустив
codesign --verify --deep --verbose /path/to/MyApp.appMyApp.app`, где `MyApp` — это имя приложения внутри распакованной папки (различается для каждого проекта). Ожидаемый результат:MyApp.app: valid on disk.
Шаг 6 : Запустите тест локально.
Вы можете запустить тест локально, чтобы проверить его поведение перед запуском в Test Lab . Для локального тестирования загрузите ваше игровое приложение в симулятор и запустите:
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
UDID вашего симулятора можно найти, выполнив команду
instruments -s devices.Если запущен только один симулятор, замените SIMULATOR_UDID на специальную строку
"booted".
Если ваш тест содержит несколько циклов, вы можете указать, какой цикл вы хотите запустить, передав номер цикла в флаг scenario . Обратите внимание, что при локальном запуске теста вы можете запустить только один цикл за раз. Например, если вы хотите запустить циклы 1, 2 и 5, вам необходимо выполнить отдельную команду для каждого цикла:
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=1xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=2xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=5
Следующие шаги
Запустите тест, используя консоль Firebase или интерфейс командной строки gcloud .
,Автоматизация тестирования игр может быть сложной задачей, особенно если игровые приложения созданы на основе различных фреймворков пользовательского интерфейса. Тесты Game Loop позволяют интегрировать ваши нативные тесты с Test Lab и легко запускать их на выбранных вами устройствах. В этом руководстве описано, как подготовить тест Game Loop для запуска с помощью Firebase Test Lab .
О тестах игрового цикла
Что такое тест игрового цикла?
Тест игрового цикла имитирует действия реального игрока, чтобы проверить, насколько хорошо ваша игра работает для пользователей, обеспечивая быструю и масштабируемую производительность. Цикл представляет собой полное или частичное выполнение теста в вашем игровом приложении. Вы можете запустить тест игрового цикла локально на симуляторе или на наборе устройств в Test Lab . Тесты игрового цикла могут использоваться для:
- Проведите игру так, как в неё играл бы конечный пользователь. Вы можете либо запрограммировать ввод данных пользователем, либо оставить пользователя в режиме ожидания, либо заменить пользователя искусственным интеллектом (например, если вы внедрили ИИ в гоночную игру, вы можете назначить водителя с ИИ для управления вводом данных пользователем).
- Запустите игру с максимальными настройками качества, чтобы узнать, какие устройства её поддерживают.
- Проведите техническое тестирование, например, скомпилируйте несколько шейдеров, выполните их и убедитесь, что результат соответствует ожиданиям.
Шаг 1 : Зарегистрируйте пользовательскую схему URL-адресов Test Lab
В Xcode выберите целевой объект проекта.
Перейдите на вкладку «Информация» , затем добавьте новый тип URL-адреса .
В поле «Схемы URL» введите
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>
Теперь ваше приложение настроено для запуска тестов с помощью Test Lab .
Шаг 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 <UIApplicationOpenURLOptionsKey, id> *)options {
if ([url.scheme isEqualToString:(@"firebase-game-loop")]) {
// ...Enter Game Loop Test logic to override application(_:open:options:).
}
}
При выполнении нескольких циклов в тесте текущий цикл передается в качестве параметра URL-адресу, используемому для запуска приложения. Номер текущего цикла также можно получить, проанализировав объект URLComponents используемый для получения пользовательской схемы URL:
Быстрый
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).
}
}
}
Завершите тест раньше времени.
По умолчанию тест игрового цикла продолжает выполнение до истечения пятиминутного таймаута, даже если все циклы выполнены. По истечении таймаута тест завершается и отменяет все ожидающие циклы. Вы можете ускорить выполнение теста или завершить его раньше, вызвав пользовательскую схему URL-адресов Test Lab firebase-game-loop-complete в AppDelegate вашего приложения. Например:
Быстрый
/// 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) {}];
}
Тест игрового цикла завершает текущий цикл и переходит к следующему. Когда циклы для выполнения заканчиваются, тест завершается.
Напишите пользовательские результаты тестирования
You can configure your Game Loop test to write custom test results to your device's file system. This way, when the test starts running, Test Lab stores the result files in a GameLoopsResults directory on your testing device (which you must create yourself). When the test ends, Test Lab moves all files from the GameLoopResults directory to your project's bucket. Keep the following in mind when setting up your test:
Все файлы с результатами загружаются независимо от типа, размера или количества файлов.
Test Lab не обрабатывает результаты ваших тестов до тех пор, пока не завершатся все циклы в вашем тесте. Поэтому, если ваш тест включает несколько циклов, записывающих результаты, убедитесь, что вы добавляете их в отдельный файл результатов или создаете отдельный файл результатов для каждого цикла. Таким образом, вы сможете избежать перезаписи результатов предыдущего цикла.
Чтобы настроить тест для записи пользовательских результатов:
В папке
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. } }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 : Подпишите ваше приложение
Убедитесь, что все артефакты в приложении подписаны. Например, это можно сделать через Xcode, указав параметры подписи, такие как профиль подготовки и идентификатор. Для получения дополнительной информации см.: Подпись Apple.
Шаг 4 : Упакуйте ваше приложение для загрузки.
Создайте IPA-файл для вашего приложения (его вам нужно будет найти позже).
В появившемся выпадающем меню выберите Продукт > Архив . Выберите самый последний архив, затем нажмите Распространить приложение .
В появившемся окне нажмите «Разработка» > «Далее» .
Нажмите «Экспорт» , затем укажите папку, в которую вы хотите загрузить IPA-файл вашего приложения.
Шаг 5 : Проверка подписи приложения
- Проверьте подпись приложения, распаковав файл .ipa и запустив
codesign --verify --deep --verbose /path/to/MyApp.appMyApp.app`, где `MyApp` — это имя приложения внутри распакованной папки (различается для каждого проекта). Ожидаемый результат:MyApp.app: valid on disk.
Шаг 6 : Запустите тест локально.
Вы можете запустить тест локально, чтобы проверить его поведение перед запуском в Test Lab . Для локального тестирования загрузите ваше игровое приложение в симулятор и запустите:
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
UDID вашего симулятора можно найти, выполнив команду
instruments -s devices.Если запущен только один симулятор, замените SIMULATOR_UDID на специальную строку
"booted".
Если ваш тест содержит несколько циклов, вы можете указать, какой цикл вы хотите запустить, передав номер цикла в флаг scenario . Обратите внимание, что при локальном запуске теста вы можете запустить только один цикл за раз. Например, если вы хотите запустить циклы 1, 2 и 5, вам необходимо выполнить отдельную команду для каждого цикла:
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=1xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=2xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=5
Следующие шаги
Запустите тест, используя консоль Firebase или интерфейс командной строки gcloud .