Автоматизировать тестирование игр может быть сложно, поскольку игровые приложения создаются на основе разных фреймворков пользовательского интерфейса. Тесты игрового цикла позволяют интегрировать нативные тесты с Test Lab и легко запускать их на выбранных устройствах. В этом руководстве описано, как подготовить тест игрового цикла для запуска с помощью Firebase Test Lab.
О тестах с игровым циклом
Что такое тест с игровым циклом?
Тестирование игрового цикла имитирует действия реального игрока, чтобы проверить, хорошо ли работает ваша игра для пользователей. Это быстрый и масштабируемый способ. Цикл – это полное или частичное тестирование мобильной игры. Вы можете запустить тестирование игрового цикла локально на симуляторе или на нескольких устройствах в Test Lab. Тесты с игровым циклом можно использовать для следующих целей:
- Пройдите игру так, как это сделал бы конечный пользователь. Вы можете либо запрограммировать действия пользователя, либо оставить его бездействующим, либо заменить его искусственным интеллектом (например, если вы реализовали ИИ в гоночной игре, вы можете поручить управление автомобилем ИИ-водителю).
- Запустите игру с самыми высокими настройками качества, чтобы узнать, какие устройства ее поддерживают.
- Выполните технический тест, например скомпилируйте несколько шейдеров, запустите их и проверьте, соответствует ли результат ожидаемому.
Шаг 1. Зарегистрируйте специальную схему URL для приложения "Test Lab"
В Xcode выберите цель проекта.
Перейдите на вкладку Информация и добавьте новый тип URL.
В поле URL Schemes (Схемы 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:):
Swift
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:
Swift
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 приложения. Пример:
Swift
/// 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 на тестовом устройстве (этот каталог нужно создать самостоятельно). После завершения теста Test Lab перемещает все файлы из каталога GameLoopResults в сегмент проекта. При настройке тестирования учитывайте следующее:
Все файлы результатов загружаются независимо от типа, размера или количества.
Test Lab не обрабатывает результаты тестирования, пока не завершатся все циклы. Если в вашем тесте несколько циклов, которые записывают выходные данные, убедитесь, что они добавляют их в уникальный файл результатов или создают файл результатов для каждого цикла. Таким образом, вы можете избежать перезаписи результатов из предыдущего цикла.
Чтобы настроить тест для записи собственных результатов, выполните следующие действия:
В каталоге
Documentsприложения создайте каталог с названиемGameLoopResults.Добавьте в код приложения (например, в делегат) следующий фрагмент:
Swift
/// 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-файл для своего приложения (вам нужно будет найти его позже).
В раскрывающемся меню выберите Товар > Архив. Выберите последний архив и нажмите Distribute App (Распространить приложение).
В открывшемся окне нажмите Development (Разработка) > Next (Далее).
Нажмите Export (Экспортировать) и укажите каталог, в который нужно скачать IPA-файл приложения.
Шаг 5. Проверьте подпись приложения
- Проверьте подпись приложения, распаковав IPA-файл и выполнив команду
codesign --verify --deep --verbose /path/to/MyApp.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 CLI.