Primeiros passos com testes de loop de jogo para iOS

Com os testes de loop de jogo, é possível escrever testes nativos para seu mecanismo de jogo e executá-los no Test Lab dos dispositivos de sua preferência. Dessa forma, você não precisa se preocupar em escrever para diferentes IUs ou frameworks de teste. Um teste de loop de jogo simula as ações de um jogador real e, ao executá-lo no Test Lab, ele fornece uma maneira rápida e escalonável de verificar se o jogo apresenta um bom desempenho para os usuários.

Esta página mostra como executar um teste de loop de jogo e, em seguida, visualizar e gerenciar os resultados do teste na página do Test Lab do Console do Firebase. Também é possível personalizar ainda mais seus testes com recursos opcionais, como gravar resultados de teste personalizados ou encerrar os testes antecipadamente.

O que é um teste de loop de jogo?

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

Primeiro, você precisa registrar o esquema de URL personalizado do Firebase Test Lab no seu app:

  1. No Xcode, selecione um destino de projeto.

  2. Clique na guia Informações e adicione um novo tipo de URL.

  3. 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ção Info.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 o Test Lab.

Etapa 2 (opcional): configurar o aplicativo para executar vários loops

Se o aplicativo tiver vários esquemas de URL personalizados registrados e você planeja executar vários loops (também conhecidos como cenários) no teste, especifique os loops que serão executados 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 &lt;UIApplicationOpenURLOptionsKey, id&gt; *)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).
        }
    }
}

Etapa 3: criar e executar um teste

Depois de registrar o esquema de URL personalizado do Test Lab, execute o teste no Console do Firebase ou com a CLI gcloud Beta. Se ainda não tiver feito isso, gere um arquivo IPA para o app (você precisará localizá-lo mais tarde).

Executar um teste no Console do Firebase

  1. Abra o Console do Firebase e crie um projeto, caso ainda não tenha feito isso.

  2. Na página "Test Lab" do Console do Firebase, clique em Executar seu primeiro teste > Executar um loop de jogo do iOS.

  3. Na seção Enviar aplicativo, clique em Procurar e, em seguida, selecione o arquivo IPA do app (caso ainda não tenha feito isso, gere um arquivo IPA para seu aplicativo).

  4. Opcional: se você quiser executar vários loops (também conhecidos como cenários) por vez ou selecionar loops específicos para execução, insira os números de loop no campo Cenários.

    Por exemplo, quando você insere "1-3, 5", o Test Lab executa os loops 1, 2, 3 e 5. Por padrão (se você não inserir nada no campo Cenários), o Test Lab só executará o loop 1.

  5. Na seção Dispositivos, selecione um ou mais dispositivos físicos em que você quer testar seu app e clique em Iniciar testes.

Executar um teste com a CLI do gcloud beta

  1. Se você ainda não tiver feito isso, configure o ambiente local do SDK da gcloud e instale o componente Beta da gcloud.

  2. Execute o comando gcloud beta firebase test ios run e use as seguintes sinalizações para configurar a execução:

Sinalizações para testes de loop de jogo
--type

Obrigatório: especifica o tipo de teste do iOS que você quer executar. É possível inserir tipos de teste xctest (padrão) ou game-loop.

--app

Obrigatório: caminho absoluto (Google Cloud Storage ou sistema de arquivos) para o arquivo IPA do seu aplicativo. Essa sinalização só é válida ao executar testes de loop de jogo.

--scenario-numbers

Os loops (também conhecidos como cenários) que você quer executar no seu aplicativo. É possível inserir um loop, uma lista ou loops, ou um intervalo de loops. O loop padrão é 1.

Por exemplo, --scenario-numbers=1-3,5 executa loops 1, 2, 3 e 5.

--device-model

O dispositivo físico em que você quer executar o teste (descubra quais dispositivos disponíveis é possível usar).

--timeout

A duração máxima do teste a ser executado. É possível inserir um número inteiro para representar a duração em segundos ou um número inteiro e uma enumeração para representar a duração como uma unidade de tempo mais longa.

Exemplo:

  • --timeout=200 força o teste a ser encerrado quando é executado até 200 segundos.
  • --timeout=1h força o teste a ser encerrado quando executado até uma hora.

Por exemplo, o comando a seguir executa um teste de loop de jogo que executa loops 1, 4, 6, 7 e 8 em um iPhone 8 Plus:

gcloud beta firebase test ios run
 --type game-loop --app path/to/my/App.ipa --scenario-numbers 1,4,6-8
 --device-model=iphone8plus

Para mais informações sobre a CLI gcloud, consulte a documentação de referência.

Executar um teste localmente

Para executar o teste localmente, carregue o app de jogos 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 loops 1, 2 e 5, será necessário executar um comando separado para cada loop:

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

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. 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 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 intervalo 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:

  1. No diretório Documents do app, crie um diretório chamado GameLoopResults.

  2. 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];
        }
    }