Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Comece com os testes do Game Loop

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

Pode ser difícil automatizar o teste de jogos quando os aplicativos de jogos são criados em diferentes estruturas de interface do usuário. Os testes de loop de jogo permitem integrar seus testes nativos com o Test Lab e executá-los facilmente nos dispositivos que você selecionar. Um teste de loop de jogo 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 loop de jogo 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 completa ou parcial do seu teste em seu 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 substituir o usuário por uma IA se 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 colocar facilmente um driver AI responsável pela entrada do usuário).
  • Execute seu jogo na 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 é a esperada etc.).

Você pode executar um teste de Game Loop em um único dispositivo de teste, um conjunto de dispositivos de teste ou no Test Lab. No entanto, não recomendamos a execução de testes de loop de jogo 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, você deve primeiro configurar seu aplicativo para testes de Game Loop.

  1. No manifesto do aplicativo, adicione um novo filtro de intenção à 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. Em 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 este código mais tarde, se preferir (por exemplo, após carregar inicialmente o mecanismo do jogo).

  3. Recomendado: Ao final do teste, adicione:

    Kotlin+KTX

    yourActivity.finish()

    Java

    yourActivity.finish();

    Isso fecha seu aplicativo quando o teste de loop de jogo é concluído. O teste depende da estrutura de interface do usuário do seu aplicativo para iniciar o próximo loop e fechar o aplicativo informa que o teste foi concluído.

Criar e executar um teste de loop de jogo

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

Executar em um dispositivo local

Test Lab's Test Loop Manager é um aplicativo de código aberto que ajuda você a integrar testes de loop de jogo 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. Em seu dispositivo, abra o aplicativo Test Loop Apps em seu telefone ou tablet. O aplicativo exibe uma lista de aplicativos em seu dispositivo que podem ser executados com loops de jogo. Se você não vir seu aplicativo de jogos 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 selecione o número de loops que deseja executar. Observação: nesta etapa, você pode optar por executar um subconjunto de loops em vez de apenas um loop. Para obter mais informações sobre como executar 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 teste

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

Use 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 o tipo de teste e clique em Continuar .
  4. Clique em Procurar e navegue até o arquivo .apk do seu aplicativo. Observação: nesta etapa, você pode optar por executar um subconjunto de loops em vez de apenas um loop. Para obter mais informações sobre como executar 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 como começar a usar o Firebase console, consulte Iniciar testes com o Firebase console.

Use a linha de comando gcloud (CLI)

  1. Se ainda não o fez, baixe e instale o Google Cloud SDK.

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

    gcloud auth login

  3. Defina seu projeto Firebase em gcloud, onde PROJECT_ID é o ID do seu projeto 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 como começar a usar a CLI gcloud, consulte Iniciar o teste 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 de loop de jogo 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 Laboratório de teste do console do Firebase (consulte Exemplo de arquivo de saída de teste de loop de jogo ).

O Test Lab segue as práticas recomendadas para compartilhar um arquivo entre aplicativos descritos 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 você deseja gravar no arquivo do lado C++ do seu aplicativo de jogo, 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 Firebase console. As áreas mostradas como /.../ podem conter quaisquer campos personalizados de que você precise, 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
}

Múltiplos loops de jogo

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

Para permitir que seu aplicativo execute vários loops de uma só vez:

  • 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" />
      

      Essa 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 permitido para um único teste). Observe que os loops são indexados a partir de 1, não 0.

    2. No aplicativo Test Loop Manager, aparece uma tela de seleção que permite selecionar qual(is) loop(s) 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 Firebase console, insira uma lista ou um 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 --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 de 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

Quando você rotula seus loops de jogo com um ou mais rótulos de cenário, você e sua equipe de controle de qualidade podem facilmente lançar 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 de um usuário real ao jogar o jogo. O objetivo do teste com esses loops é encontrar problemas que um usuário real enfrentaria durante o jogo.
  • com.google.test.loops.gpu_compatibility : For 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 : For loops usados ​​para testar uma ampla variedade de problemas de compatibilidade, incluindo problemas de E/S e OpenSSL.
  • com.google.test.loops.performance : For 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 escolha:

      <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 um conjunto de inteiros de 1 a 1024 (o número máximo de loops permitidos para um único teste) que representam os loops que 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 --scenario-labels (por exemplo, --scenario-labels=performance,gpu ).

Suporte de 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 com êxito o licenciamento 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 carregar seu aplicativo no Test Lab.

Problemas conhecidos

Os testes de loop de jogo no Test Lab têm os seguintes problemas conhecidos:

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