Comece com os testes do Game Loop

Pode ser difícil automatizar os testes de jogos quando os aplicativos de jogos são criados em diferentes estruturas de UI. Os testes do Game Loop permitem integrar seus testes nativos ao Test Lab e executá-los facilmente nos dispositivos que você selecionar. Um teste Game Loop executa seu teste por meio de seu aplicativo de jogo enquanto simula as ações de um jogador real. Este guia mostra como executar um teste de Game Loop e, em seguida, visualizar e gerenciar os resultados do teste no console do Firebase.

Dependendo do seu mecanismo de jogo, você pode implementar testes com loops únicos ou múltiplos. Um loop é uma execução total ou parcial do teste no aplicativo de jogos. Os loops de jogo podem ser usados ​​para:

  • Execute um nível do seu jogo da mesma forma que um usuário final o jogaria. Você pode criar um script para a entrada do usuário, deixá-lo ocioso ou substituí-lo por uma IA se isso fizer sentido em seu jogo (por exemplo, digamos que você tenha um aplicativo de jogos de carros de corrida e já tenha uma IA implementada. Você pode facilmente colocar um driver de IA responsável pela entrada do usuário).
  • Execute seu jogo com a configuração de qualidade mais alta para ver se os dispositivos são compatíveis.
  • Execute um teste técnico (compile vários shaders, execute-os, verifique se a saída está conforme o esperado, etc).

Você pode executar um teste de Game Loop em um único dispositivo de teste, em um conjunto de dispositivos de teste ou no Test Lab. No entanto, não recomendamos a execução de testes de Game Loop em dispositivos virtuais porque eles têm taxas de quadros gráficos mais baixas do que os dispositivos físicos.

Antes de você começar

Para implementar um teste, primeiro você deve configurar seu aplicativo para testes de Game Loop.

  1. No manifesto do seu aplicativo, adicione um novo filtro de intent à sua atividade :

    <activity android:name=".MyActivity">
       <intent-filter>
           <action android:name="com.google.intent.action.TEST_LOOP"/>
           <category android:name="android.intent.category.DEFAULT"/>
           <data android:mimeType="application/javascript"/>
       </intent-filter>
       <intent-filter>
          ... (other intent filters here)
       </intent-filter>
    </activity>
    

    Isso permite que o Test Lab inicie seu jogo acionando-o com uma intenção específica.

  2. No seu código (recomendamos dentro da declaração do método onCreate ), adicione o seguinte:

    Kotlin+KTX

    val launchIntent = intent
    if (launchIntent.action == "com.google.intent.action.TEST_LOOP") {
        val scenario = launchIntent.getIntExtra("scenario", 0)
        // Code to handle your game loop here
    }

    Java

    Intent launchIntent = getIntent();
    if(launchIntent.getAction().equals("com.google.intent.action.TEST_LOOP")) {
        int scenario = launchIntent.getIntExtra("scenario", 0);
        // Code to handle your game loop here
    }

    Isso permite que sua atividade verifique a intenção que a inicia. Você também pode adicionar esse código mais tarde, se preferir (por exemplo, após carregar inicialmente o mecanismo do jogo).

  3. Recomendado: No final do teste, adicione:

    Kotlin+KTX

    yourActivity.finish()

    Java

    yourActivity.finish();

    Isso fecha seu aplicativo quando o teste do Game Loop for concluído. O teste depende da estrutura de UI do seu aplicativo para iniciar o próximo loop, e fechar o aplicativo informa que o teste foi concluído.

Crie e execute um teste de Game Loop

Depois de configurar seu aplicativo para testes de Game Loop, você pode criar imediatamente um teste e executá-lo em seu aplicativo de jogos. Você pode optar por executar um teste no Test Lab usando o console do Firebase ou a interface de linha de comando (CLI) gcloud ou em um dispositivo local usando o Test Loop Manager .

Execute em um dispositivo local

O Test Loop Manager do Test Lab é um aplicativo de código aberto que ajuda a integrar testes de Game Loop e executá-los em seus dispositivos locais. Ele também permite que sua equipe de garantia de qualidade execute os mesmos loops de jogo em seus dispositivos.

Para executar um teste em um dispositivo local usando o Test Loop Manager:

  1. Baixe o Test Loop Manager em um telefone ou tablet e instale-o executando:
    adb install testloopmanager.apk
  2. No seu dispositivo, abra o aplicativo Test Loop Apps no seu telefone ou tablet. O aplicativo exibe uma lista de aplicativos no seu dispositivo que podem ser executados com loops de jogo. Se você não encontrar seu aplicativo de jogo aqui, certifique-se de que seu filtro de intenção corresponda ao descrito na primeira etapa da seção Antes de começar .
  3. Selecione seu aplicativo de jogo e o número de loops que deseja executar. Nota: Nesta etapa, você pode optar por executar um subconjunto de loops em vez de apenas um loop. Para obter mais informações sobre a execução de vários loops de uma só vez, consulte Recursos opcionais .
  4. Clique em Executar teste . Seu teste começa a ser executado imediatamente.

Executar no laboratório de testes

Você pode executar um teste de Game Loop no Test Lab usando o console do Firebase ou a CLI gcloud. Antes de começar, se ainda não o fez, abra o console do Firebase e crie um projeto.

Usar o console do Firebase

  1. No console do Firebase, clique em Test Lab no painel esquerdo.
  2. Clique em Executar seu primeiro teste (ou Executar um teste se seu projeto já tiver executado um teste).
  3. Selecione Game Loop como tipo de teste e clique em Continuar .
  4. Clique em Procurar e navegue até o arquivo .apk do seu aplicativo. Nota: Nesta etapa, você pode optar por executar um subconjunto de loops em vez de apenas um loop. Para obter mais informações sobre a execução de vários loops de uma só vez, consulte Recursos opcionais .
  5. Clique em Continuar .
  6. Selecione os dispositivos físicos a serem usados ​​para testar seu aplicativo.
  7. Clique em Iniciar testes .

Para obter mais informações sobre os primeiros passos com o Firebase console, consulte Iniciar testes com o Firebase console.

Use a linha de comando gcloud (CLI)

  1. Se ainda não o fez, faça o download e instale o SDK do Google Cloud

  2. Faça login na CLI gcloud usando sua Conta do Google:

    gcloud auth login

  3. Defina seu projeto do Firebase no gcloud, onde PROJECT_ID é o ID do seu projeto do Firebase:

    gcloud config set project PROJECT_ID
    
  4. Execute seu primeiro teste:

    gcloud firebase test android run \
     --type=game-loop --app=<var>path-to-apk</var> \
     --device model=herolte,version=23
    

Para obter mais informações sobre os primeiros passos com a CLI gcloud, consulte Iniciar testes na linha de comando gcloud.

Recursos opcionais

O Test Lab oferece vários recursos opcionais que permitem personalizar ainda mais seus testes, incluindo a capacidade de gravar dados de saída, suporte para vários loops de jogo e rótulos para loops relacionados.

Gravar dados de saída

Seu teste Game Loop pode gravar a saída em um arquivo especificado no método launchIntent.getData() . Depois de executar um teste, você pode acessar esses dados de saída na seção Test Lab do console do Firebase (consulte Exemplo de arquivo de saída de teste do Game Loop ).

O Test Lab segue as práticas recomendadas para compartilhar um arquivo entre aplicativos descritas em Compartilhando um arquivo . No método onCreate() da sua atividade, onde sua intenção está localizada, você pode verificar seu arquivo de saída de dados executando o seguinte código:

Kotlin+KTX

val launchIntent = intent
val logFile = launchIntent.data
logFile?.let {
    Log.i(TAG, "Log file ${it.encodedPath}")
    // ...
}

Java

Intent launchIntent = getIntent();
Uri logFile = launchIntent.getData();
if (logFile != null) {
    Log.i(TAG, "Log file " + logFile.getEncodedPath());
    // ...
}

Se quiser gravar no arquivo do lado C++ do seu aplicativo de jogo, você pode passar o descritor de arquivo em vez do caminho do arquivo:

Kotlin+KTX

val launchIntent = intent
val logFile = launchIntent.data
var fd = -1
logFile?.let {
    Log.i(TAG, "Log file ${it.encodedPath}")
    fd = try {
        contentResolver
            .openAssetFileDescriptor(logFile, "w")!!
            .parcelFileDescriptor
            .fd
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
        -1
    } catch (e: NullPointerException) {
        e.printStackTrace()
        -1
    }
}

// C++ code invoked here.
// native_function(fd);

Java

Intent launchIntent = getIntent();
Uri logFile = launchIntent.getData();
int fd = -1;
if (logFile != null) {
    Log.i(TAG, "Log file " + logFile.getEncodedPath());
    try {
        fd = getContentResolver()
                .openAssetFileDescriptor(logFile, "w")
                .getParcelFileDescriptor()
                .getFd();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        fd = -1;
    } catch (NullPointerException e) {
        e.printStackTrace();
        fd = -1;
    }
}

// C++ code invoked here.
// native_function(fd);

C++

#include <unistd.h>
JNIEXPORT void JNICALL
Java_my_package_name_MyActivity_native_function(JNIEnv *env, jclass type, jint log_file_descriptor) {
// The file descriptor needs to be duplicated.
int my_file_descriptor = dup(log_file_descriptor);
}

Exemplo de arquivo de saída

Você pode usar arquivos de dados de saída (formatados como no exemplo abaixo) para exibir os resultados do teste de loop de jogo na seção Test Lab do console do Firebase. As áreas mostradas como /.../ podem conter quaisquer campos personalizados necessários, desde que não entrem em conflito com os nomes de outros campos usados ​​neste arquivo:

{
  "name": "test name",
  "start_timestamp": 0, // Timestamp of the test start (in us).
                           Can be absolute or relative
  "driver_info": "...",
  "frame_stats": [
    {
      "timestamp": 1200000, // Timestamp at which this section was written
                               It contains value regarding the period
                               start_timestamp(0) -> this timestamp (1200000 us)
      "avg_frame_time": 15320, // Average time to render a frame in ns
      "nb_swap": 52, // Number of frame rendered
      "threads": [
        {
          "name": "physics",
          "Avg_time": 8030 // Average time spent in this thread per frame in us
        },
        {
          "name": "AI",
          "Avg_time": 2030 // Average time spent in this thread per frame in us
        }
      ],
      /.../ // Any custom field you want (vertices display on the screen, nb units …)
    },
    {
      // Next frame data here, same format as above
    }
  ],
  "loading_stats": [
    {
      "name": "assets_level_1",
      "total_time": 7850, // in us
      /.../
    },
    {
      "name": "victory_screen",
      "total_time": 554, // in us
      /.../
    }

  ],
  /.../, // You can add custom fields here
}

Vários loops de jogo

Talvez seja útil executar vários loops de jogo no seu aplicativo. Um loop é uma execução completa do seu aplicativo de jogo, do início ao fim. Por exemplo, se você tiver vários níveis no jogo, talvez queira ter um loop de jogo para iniciar cada nível, em vez de ter um loop que itera por todos eles. Dessa forma, se o seu aplicativo travar no nível 32, você poderá iniciar diretamente o loop do jogo para reproduzir a falha e testar as correções de bugs.

Para permitir que seu aplicativo execute vários loops ao mesmo tempo:

  • Se você estiver executando um teste com o Test Loop Manager:

    1. Adicione a seguinte linha ao manifesto do seu aplicativo, dentro do elemento <application> :

      <meta-data
        android:name="com.google.test.loops"
        android:value="5" />
      

      Esta intenção de inicialização contém o loop de destino como um parâmetro inteiro. No campo android:value , você pode especificar um número inteiro de 1 a 1024 (o número máximo de loops permitidos para um único teste). Observe que os loops são indexados a partir de 1, não de 0.

    2. No aplicativo Test Loop Manager, aparece uma tela de seleção que permite selecionar quais loops você deseja executar. Se você selecionar vários loops, cada loop será iniciado em sequência após a conclusão do loop anterior.

  • Se você estiver executando um teste com o console do Firebase, insira uma lista ou intervalo de números de loop no campo Cenários .

  • Se você estiver executando um teste com a CLI gcloud, especifique uma lista de números de loop usando a sinalização --scenario-numbers . Por exemplo, --scenario-numbers=1,3,5 executa os loops 1, 3 e 5.

  • Se você estiver escrevendo C++ e quiser alterar o comportamento do seu loop, passe o seguinte extra para seu código C++ nativo:

    Kotlin+KTX

    val launchIntent = intent
    val scenario = launchIntent.getIntExtra("scenario", 0)

    Java

    Intent launchIntent = getIntent();
    int scenario = launchIntent.getIntExtra("scenario", 0);

    Agora você pode alterar o comportamento do seu loop com base no valor int resultante.

Rotule os loops do jogo

Ao rotular seus loops de jogo com um ou mais rótulos de cenário, você e sua equipe de controle de qualidade podem facilmente iniciar um conjunto de loops de jogo relacionados (por exemplo, "todos os loops de jogo de compatibilidade") e testá-los em uma única matriz. Você pode criar seus próprios rótulos ou usar os rótulos predefinidos oferecidos pelo Test Lab:

  • com.google.test.loops.player_experience : For loops usados ​​para reproduzir a experiência real de um usuário ao jogar. O objetivo dos testes com esses loops é encontrar problemas que um usuário real enfrentaria ao jogar.
  • com.google.test.loops.gpu_compatibility : Para loops usados ​​para testar problemas relacionados à GPU. O objetivo do teste com esses loops é executar o código da GPU que pode não funcionar corretamente na produção, para expor problemas com hardware e drivers.
  • com.google.test.loops.compatibility : loops For usados ​​para testar uma ampla gama de problemas de compatibilidade, incluindo problemas de E/S e problemas de OpenSSL.
  • com.google.test.loops.performance : para loops usados ​​para testar o desempenho do dispositivo. Por exemplo, um jogo pode ser executado nas configurações gráficas mais complexas para ver como um novo dispositivo se comporta.

Para permitir que seu aplicativo execute loops com o mesmo rótulo:

  • Se você estiver executando um teste com o Test Loop Manager:

    1. No manifesto do seu aplicativo, adicione a seguinte linha de metadados e substitua LABEL_NAME por um rótulo de sua preferência:

      <meta-data
       android:name="com.google.test.loops.LABEL_NAME"
       android:value="1,3-5" />
      

      No campo android:value , você pode especificar um intervalo ou conjunto de números inteiros de 1 a 1024 (o número máximo de loops permitidos para um único teste) que representam os loops que você deseja rotular. Observe que os loops são indexados a partir de 1, não de 0. Por exemplo, android:value="1,3-5" aplica LABEL_NAME aos loops 1, 3, 4 e 5.

    2. No aplicativo Test Loop Manager, insira um ou mais rótulos no campo Rótulos .

  • Se você estiver executando um teste com o Firebase Console, insira um ou mais rótulos no campo Rótulos .

  • Se você estiver executando um teste com a CLI gcloud, especifique um ou mais rótulos de cenário usando a sinalização --scenario-labels (por exemplo, --scenario-labels=performance,gpu ).

Suporte para licenciamento de aplicativos

O Test Lab oferece suporte a aplicativos que usam o serviço de licenciamento de aplicativos oferecido pelo Google Play. Para verificar o licenciamento com sucesso ao testar seu aplicativo com o Test Lab, você deve publicar seu aplicativo no canal de produção na Play Store. Para testar seu aplicativo no canal alfa ou beta usando o Test Lab, remova a verificação de licenciamento antes de enviar seu aplicativo para o Test Lab.

Problemas conhecidos

Os testes de Game Loop no Test Lab apresentam os seguintes problemas conhecidos:

  • Algumas falhas não suportam backtraces. Por exemplo, algumas compilações de versão podem suprimir a saída do processo debuggerd usando prctl(PR_SET_DUMPABLE, 0) . Para saber mais, consulte debuggerd .
  • A API nível 19 não é suportada atualmente devido a erros de permissão de arquivo.