Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Inizia con i test di Game Loop

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Può essere difficile automatizzare i test di gioco quando le app di gioco sono basate su diversi framework dell'interfaccia utente. I test di Game Loop ti consentono di integrare i tuoi test nativi con Test Lab ed eseguirli facilmente sui dispositivi selezionati. Un test Game Loop esegue il test attraverso la tua app di gioco simulando le azioni di un giocatore reale. Questa guida mostra come eseguire un test di Game Loop, quindi visualizzare e gestire i risultati del test nella console Firebase.

A seconda del tuo motore di gioco, puoi implementare test con loop singoli o multipli . Un ciclo è un ciclo completo o parziale del test sull'app di gioco. I loop di gioco possono essere utilizzati per:

  • Esegui un livello del tuo gioco nello stesso modo in cui lo giocherebbe un utente finale. Puoi scrivere l'input dell'utente, lasciare che l'utente sia inattivo o sostituire l'utente con un'IA se ha senso nel tuo gioco (ad esempio, supponi di avere un'app di gioco per auto da corsa e di avere già un'IA implementata. Puoi mettere facilmente un driver AI responsabile dell'input dell'utente).
  • Esegui il gioco con l'impostazione di qualità più alta per vedere se i dispositivi la supportano.
  • Eseguire un test tecnico (compilare più shader, eseguirli, verificare che l'output sia come previsto, ecc.).

Puoi eseguire un test Game Loop su un singolo dispositivo di test, un set di dispositivi di test o su Test Lab. Tuttavia, non consigliamo di eseguire i test di Game Loop su dispositivi virtuali perché hanno frame rate grafici inferiori rispetto ai dispositivi fisici.

Prima di iniziare

Per implementare un test, devi prima configurare la tua app per i test di Game Loop.

  1. Nel manifest dell'app, aggiungi un nuovo filtro intento alla tua attività :

    <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>
    

    Ciò consente a Test Lab di avviare il gioco attivandolo con un intento specifico.

  2. Nel tuo codice (ti consigliamo all'interno della dichiarazione del metodo onCreate ), aggiungi quanto segue:

    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
    }

    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
    }

    Ciò consente alla tua attività di verificare l'intento che la avvia. Puoi anche aggiungere questo codice in un secondo momento, se preferisci (ad esempio, dopo aver inizialmente caricato il tuo motore di gioco).

  3. Consigliato: Al termine del test, aggiungere:

    Java

    yourActivity.finish();

    Kotlin+KTX

    yourActivity.finish()

    Questa operazione chiude l'app al termine del test di Game Loop. Il test si basa sul framework dell'interfaccia utente dell'app per avviare il ciclo successivo e la chiusura dell'app indica che il test è terminato.

Crea ed esegui un test di Game Loop

Dopo aver configurato la tua app per i test di Game Loop, puoi creare immediatamente un test ed eseguirlo nella tua app di gioco. Puoi scegliere di eseguire un test in Test Lab utilizzando la console Firebase o l' interfaccia a riga di comando (CLI) gcloud o su un dispositivo locale utilizzando Test Loop Manager .

Esegui su un dispositivo locale

Test Loop Manager di Test Lab è un'app open source che ti aiuta a integrare i test di Game Loop ed eseguirli sui tuoi dispositivi locali. Consente inoltre al tuo team di garanzia della qualità di eseguire gli stessi cicli di gioco sui propri dispositivi.

Per eseguire un test su un dispositivo locale utilizzando Test Loop Manager:

  1. Scarica Test Loop Manager su un telefono o tablet e installalo eseguendo:
    adb install testloopmanager.apk
  2. Sul tuo dispositivo, apri l'app Test Loop Apps sul tuo telefono o tablet. L'app mostra un elenco di app sul tuo dispositivo che possono essere eseguite con loop di gioco. Se non vedi la tua app di gioco qui, assicurati che il tuo filtro intento corrisponda a quello descritto nel primo passaggio della sezione Prima di iniziare .
  3. Seleziona la tua app di gioco, quindi seleziona il numero di loop che desideri eseguire. Nota: a questo punto, puoi scegliere di eseguire un sottoinsieme di cicli anziché un solo ciclo. Per ulteriori informazioni sull'esecuzione di più loop contemporaneamente, vedere Funzionalità opzionali.
  4. Fare clic su Esegui test . Il test inizia a essere eseguito immediatamente.

Esegui in laboratorio di prova

Puoi eseguire un test di Game Loop in Test Lab utilizzando la console Firebase o l' interfaccia a riga di comando gcloud. Prima di iniziare, se non l'hai già fatto, apri la console Firebase e crea un progetto.

Usa la console Firebase

  1. Nella console Firebase, fai clic su Test Lab nel pannello di sinistra.
  2. Fai clic su Esegui il tuo primo test (o Esegui un test se il tuo progetto ha già eseguito un test).
  3. Seleziona Game Loop come tipo di test, quindi fai clic su Continua .
  4. Fai clic su Sfoglia , quindi cerca il file .apk dell'app. Nota: a questo punto, puoi scegliere di eseguire un sottoinsieme di cicli anziché un solo ciclo. Per ulteriori informazioni sull'esecuzione di più loop contemporaneamente, vedere Funzionalità opzionali.
  5. Fare clic su Continua .
  6. Seleziona i dispositivi fisici da utilizzare per testare la tua app.
  7. Fare clic su Avvia test .

Per ulteriori informazioni su come iniziare con la console Firebase, consulta Iniziare i test con la console Firebase.

Utilizzare la riga di comando (CLI) di gcloud

  1. Se non l'hai già fatto, scarica e installa Google Cloud SDK.

  2. Accedi alla CLI di gcloud utilizzando il tuo account Google:

    gcloud auth login

  3. Imposta il tuo progetto Firebase in gcloud, dove PROJECT_ID è l'ID del tuo progetto Firebase:

    gcloud config set project PROJECT_ID
    
  4. Esegui il tuo primo test:

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

Per ulteriori informazioni su come iniziare con l'interfaccia a riga di comando di gcloud, consulta Avviare il test dalla riga di comando di gcloud.

Caratteristiche opzionali

Test Lab offre diverse funzionalità opzionali che ti consentono di personalizzare ulteriormente i tuoi test, inclusa la possibilità di scrivere dati di output, supporto per più loop di gioco ed etichette per loop correlati.

Scrivi i dati di output

Il test di Game Loop può scrivere l'output in un file specificato nel metodo launchIntent.getData() . Dopo aver eseguito un test, puoi accedere a questi dati di output nella sezione Test Lab della console Firebase (vedi Esempio di file di output del test di Game Loop ).

Test Lab segue le best practice per la condivisione di un file tra le app descritte in Condivisione di un file . Nel metodo onCreate() della tua attività, in cui si trova il tuo intento, puoi controllare il file di output dei dati eseguendo il codice seguente:

Java

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

Kotlin+KTX

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

Se vuoi scrivere sul file dal lato C++ della tua app di gioco, puoi passare il descrittore di file invece del percorso del file:

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);

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);

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);
}

Esempio di file di output

Puoi utilizzare i file di dati di output (formattati come nell'esempio seguente) per visualizzare i risultati del test del loop di gioco nella sezione Test Lab della console Firebase. Le aree mostrate come /.../ possono contenere tutti i campi personalizzati di cui hai bisogno, purché non siano in conflitto con i nomi di altri campi utilizzati in questo file:

{
  "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
}

Più cicli di gioco

Potresti trovare utile eseguire più cicli di gioco nella tua app. Un ciclo è un'analisi completa dell'app di gioco dall'inizio alla fine. Ad esempio, se hai più livelli nel tuo gioco, potresti voler avere un ciclo di gioco per avviare ogni livello invece di avere un ciclo che li ripeta tutti. In questo modo, se la tua app si arresta in modo anomalo al livello 32, puoi avviare direttamente quel ciclo di gioco per riprodurre l'arresto anomalo e testare le correzioni dei bug.

Per consentire alla tua app di eseguire più loop contemporaneamente:

  • Se stai eseguendo un test con Test Loop Manager:

    1. Aggiungi la seguente riga al manifest della tua app, all'interno dell'elemento <application> :

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

      Questo intento di avvio contiene il ciclo di destinazione come parametro intero. Nel campo android:value , puoi specificare un numero intero compreso tra 1 e 1024 (il numero massimo di loop consentiti per un singolo test). Nota che i loop sono indicizzati a partire da 1, non da 0.

    2. Nell'app Test Loop Manager, viene visualizzata una schermata di selezione che ti consente di selezionare i loop che desideri eseguire. Se si selezionano più cicli, ogni ciclo viene avviato in sequenza al termine del ciclo precedente.

  • Se stai eseguendo un test con la console Firebase, inserisci un elenco o un intervallo di numeri di loop nel campo Scenari .

  • Se stai eseguendo un test con l'interfaccia a riga di comando di gcloud, specifica un elenco di numeri di loop utilizzando il --scenario-numbers . Ad esempio, --scenario-numbers=1,3,5 esegue i cicli 1, 3 e 5.

  • Se stai scrivendo C++ e vuoi cambiare il comportamento del tuo ciclo, passa il seguente extra al tuo codice C++ nativo:

    Java

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

    Kotlin+KTX

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

    Ora puoi modificare il comportamento del tuo ciclo in base al valore int risultante.

Etichetta i loop di gioco

Quando etichetti i tuoi loop di gioco con una o più etichette di scenario, tu e il tuo team QA potete facilmente avviare una serie di loop di gioco correlati (ad esempio, "tutti i loop di gioco di compatibilità") e testarli in un'unica matrice. Puoi creare le tue etichette o utilizzare le etichette predefinite offerte da Test Lab:

  • com.google.test.loops.player_experience : Per i loop utilizzati per riprodurre l'esperienza di un utente reale durante il gioco. L'obiettivo del test con questi loop è trovare i problemi che un utente reale dovrebbe affrontare durante il gioco.
  • com.google.test.loops.gpu_compatibility : loop For utilizzati per testare problemi relativi alla GPU. L'obiettivo del test con questi loop è eseguire codice GPU che potrebbe non essere eseguito correttamente in produzione, per esporre problemi con hardware e driver.
  • com.google.test.loops.compatibility : loop For utilizzati per testare un'ampia gamma di problemi di compatibilità, inclusi problemi di I/O e problemi di OpenSSL.
  • com.google.test.loops.performance : cicli For utilizzati per testare le prestazioni del dispositivo. Ad esempio, un gioco potrebbe essere eseguito con le impostazioni grafiche più complesse per vedere come si comporta un nuovo dispositivo.

Per consentire alla tua app di eseguire loop con la stessa etichetta:

  • Se stai eseguendo un test con Test Loop Manager:

    1. Nel file manifest della tua app, aggiungi la seguente riga di metadati e sostituisci LABEL_NAME con un'etichetta a tua scelta:

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

      Nel campo android:value , puoi specificare un intervallo o un insieme di numeri interi da 1 a 1024 (il numero massimo di loop consentiti per un singolo test) che rappresentano i loop che desideri etichettare. Nota che i loop sono indicizzati a partire da 1, non da 0. Ad esempio, android:value="1,3-5" applica LABEL_NAME ai loop 1, 3, 4 e 5.

    2. Nell'app Test Loop Manager, inserisci una o più etichette nel campo Etichette .

  • Se stai eseguendo un test con la console Firebase, inserisci una o più etichette nel campo Etichette .

  • Se stai eseguendo un test con l'interfaccia a riga di comando gcloud, specifica una o più etichette di scenario utilizzando il --scenario-labels (ad esempio, --scenario-labels=performance,gpu ).

Supporto per la licenza dell'app

Test Lab supporta le app che utilizzano il servizio di licenza delle app offerto da Google Play. Per verificare correttamente la licenza durante il test della tua app con Test Lab, devi pubblicare la tua app nel canale di produzione nel Play Store. Per testare la tua app nel canale alfa o beta utilizzando Test Lab, rimuovi il controllo delle licenze prima di caricare l'app in Test Lab.

Problemi noti

I test di Game Loop in Test Lab presentano i seguenti problemi noti:

  • Alcuni arresti anomali non supportano i backtrace. Ad esempio, alcune build di rilascio possono sopprimere l'output del processo debuggerd utilizzando prctl(PR_SET_DUMPABLE, 0) . Per ulteriori informazioni, vedere debuggerd .
  • Il livello API 19 non è attualmente supportato a causa di errori di autorizzazione dei file.