Pode ser difícil automatizar testes de jogos quando esses apps são criados em diferentes frameworks de interface. Os testes de loop de jogo permitem que você integre seus testes nativos com o Test Lab e os execute facilmente nos dispositivos selecionados. Isso descreve como preparar um teste de loop de jogo para execução usando Firebase Test Lab.
Sobre os testes de loop de jogo
O que é um teste de loop de jogo?
Um teste de loop de jogo simula as ações de um jogador real para verificar se o jogo tem um bom desempenho para os usuários de maneira rápida e escalonável. Um loop é uma execução completa ou parcial do teste no seu app de jogos. É possível executar um teste de loop de jogo localmente em um simulador ou em um conjunto de dispositivos no Test Lab. Os testes de loop de jogo podem ser usados para:
- Executar seu jogo como um usuário final. É possível criar um script para a entrada do usuário, deixar o usuário inativo ou substituir o usuário por uma IA (por exemplo, se você tiver implementado a IA em um jogo de corrida de carros, será possível colocar um motorista de IA no comando da entrada do usuário).
- Executar seu jogo na configuração de qualidade mais alta para descobrir quais dispositivos são compatíveis.
- Executar um teste técnico, como compilar vários sombreadores, executá-los e verificar se a saída está conforme o esperado.
Etapa 1: registrar o esquema de URL personalizado do Test Lab
No Xcode, selecione um destino de projeto.
Clique na guia Informações e adicione um novo tipo de URL.
No campo Esquemas de URL, insira
firebase-game-loop
. Também é possível registrar o esquema de URL personalizado adicionando-o ao arquivo de configuraçãoInfo.plist
do projeto em qualquer lugar na tag<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>
Seu app agora está configurado para executar um teste usando Test Lab.
Etapa 2: configurar seu app (opcional)
Executar vários loops
Se você pretende executar vários loops (também conhecido como cenários) no teste, especifique quais loops quer executar no app no momento da inicialização.
Na delegação do app, modifique o método 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:).
}
}
Quando você executa vários loops no teste, o loop atual é passado como um parâmetro para o URL usado para iniciar o aplicativo. Também é possível conseguir o número do loop atual analisando o objeto URLComponents
usado para buscar o esquema de URL personalizado:
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).
}
}
}
Encerrar um teste antecipadamente
Por padrão, um teste de loop de jogo continua em execução até atingir o tempo limite de cinco minutos, mesmo quando todos os loops foram executados. Quando o tempo limite é atingido, o teste termina e cancela todos os loops pendentes. É possível acelerar seu teste ou encerrá-lo antecipadamente chamando o esquema de URL personalizado do Test Lab
firebase-game-loop-complete
no AppDelegate do app. Por exemplo:
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) {}];
}
Seu teste de loop de jogo encerra o loop atual e executa o próximo loop. Quando não houver mais loops a serem executados, o teste será encerrado.
Gravar resultados de teste personalizados
É possível configurar seu teste de loop de jogo para gravar resultados de teste personalizados no sistema de arquivos do seu dispositivo. Dessa forma, quando o teste começa a ser executado, o Test Lab armazena os arquivos de resultado em um diretório do GameLoopsResults
no seu dispositivo de teste (que você mesmo precisa criar). Quando o teste termina, o Test Lab move todos os arquivos do diretório GameLoopResults
para o bucket do projeto. Lembre-se do seguinte ao configurar seu teste:
Todos os arquivos de resultados são enviados independentemente do tipo, tamanho ou quantidade do arquivo.
O Test Lab não processa os resultados do teste até que todos os loops do teste terminem de ser executados. Portanto, se o teste incluir vários loops que gravam a saída, anexe-os a um único arquivo de resultado ou crie um arquivo de resultado para cada loop. Dessa forma, é possível evitar a substituição de resultados de um loop anterior.
Para configurar seu teste para gravar resultados de teste personalizados, siga as etapas a seguir:
No diretório
Documents
do app, crie um diretório chamadoGameLoopResults
.Em qualquer lugar no código do app (por exemplo, a delegação do app), adicione o seguinte:
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]; } }
Etapa 3: assinar o app
Verifique se todos os artefatos no app estão assinados. Por exemplo, é possível fazer isso pelo Xcode especificando configurações de assinatura, como provisionamento de perfil e identidade. Para mais informações, consulte Assinatura de código da Apple
Etapa 4: criar um pacote do app para upload
Gere um arquivo IPA para seu app (será necessário localizá-lo mais tarde).
No menu suspenso que é exibido, clique em Produto > Arquivo. Selecione o arquivo mais recente e clique em Distribuir aplicativo.
Na janela exibida, clique em Desenvolvimento > Avançar.
Opcional: para ter uma versão mais rápida, desmarque a opção Reconstruir pelo Bitcode e clique em Avançar. O Test Lab não exige a redução ou a recriação do app para executar um teste. Assim, é possível desativar essa opção com segurança.
Clique em Exportar e insira um diretório em que você quer fazer o download do arquivo IPA do seu app.
Etapa 5: verificar a assinatura do app
- Verifique a assinatura do app descompactando o arquivo .ipa e executando
codesign --verify --deep --verbose /path/to/MyApp.app
, em que "MyApp" é o nome do app dentro da pasta descompactada (varia para cada projeto). A saída esperada éMyApp.app: valid on disk
.
Etapa 6: executar seu teste localmente
É possível executar seu teste localmente para verificar o comportamento dele antes de executá-lo com o Test Lab. Para testar localmente, carregue seu aplicativo de jogo em um simulador e execute:
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
Para encontrar o UDID do simulador, execute o comando
instruments -s devices
.Se houver apenas um simulador em execução, insira a string especial
"booted"
no lugar de SIMULATOR_UDID.
Se o teste contiver vários loops, especifique qual loop você quer executar transmitindo o número do loop para a sinalização scenario
. Só é possível executar um loop por vez ao executar o teste localmente. Por exemplo, se você
quiser executar os loops 1, 2 e 5, será necessário executar um comando separado para cada um:
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
Próximas etapas
Execute o teste usando o Console do Firebase ou a gcloud CLI.