Erste Schritte mit Spielschleifentests

Es kann schwierig sein, das Testen von Spielen zu automatisieren, wenn Gaming-Apps auf verschiedenen UI-Frameworks basieren. Mit Spielschleifen-Tests können Sie Ihre nativen Tests in Test Lab einbinden und sie ganz einfach auf den von Ihnen ausgewählten Geräten ausführen. Bei einem Spielschleifen-Test wird Ihr Test in Ihrer Gaming-App ausgeführt, während die Aktionen eines echten Spielers simuliert werden. In dieser Anleitung erfahren Sie, wie Sie einen Spielschleife-Test ausführen und die Testergebnisse in der Firebase Console ansehen und verwalten.

Was ist ein Spielschleifentest?

Da Gaming-Apps in verschiedenen UI-Frameworks und Engines wie Unity, Unreal oder OpenGL/Vulkan C++-Code gerendert werden, können Standardautomatisierungstools UI-Elemente nicht untersuchen oder mit ihnen interagieren. Mit einem Spielschleifentest können Sie Ihre nativen Engine-Tests in Test Lab einbinden, indem Sie Ihr Spiel mit einer Absicht starten, die eine bestimmte Szenarionummer enthält. Diese Szenarionummer veranlasst Ihre App, vorskriptierte Logik, KI-Simulationen oder Leistungsprüfungen direkt in Ihrer Spiele-Engine auszuführen.

Nach dem Start interagiert Test Lab nicht mehr mit der Benutzeroberfläche Ihres Spiels. Stattdessen fungiert Test Lab als Testtransport und -umgebung: Es wird das jeweilige Szenario gestartet, auf Abstürze und Zeitüberschreitungen wird geachtet und alle benutzerdefinierten Ergebnislogs werden erfasst, wenn Ihre App die Schleife beendet hat.

Unterschiede zwischen Game-Loops und Instrumentierungstests

  • Instrumentierungstests (z. B. Espresso oder UI Automator) basieren auf externen Frameworks, um UI-Interaktionen zu steuern, auf Schaltflächen zu klicken und den Anwendungsstatus in der Android-View-Hierarchie von außerhalb Ihrer App zu bestätigen.
  • Bei Game-Loop-Tests wird die Testlogik an Ihre App delegiert. Ihre App führt ihren eigenen internen Testlauf oder ihre eigene Simulation ohne externe UI-Interaktion aus, während Test Lab Ihr Szenario auslöst und die Testausgabe erfasst.

Beispiele

Angenommen, Sie möchten überprüfen, ob Ihr Spiel auf verschiedenen physischen Geräten mindestens 60 Frames pro Sekunde erreicht. Sie können das Szenario 1 in Ihrem Spielcode implementieren, um das visuell komplexeste Level zu laden und einen KI-Player oder ein automatisiertes Script zwei Minuten lang spielen zu lassen.

Wenn Test Lab das Szenario 1 auslöst, startet das Spiel den KI-Durchlauf, überwacht die Frame-Rendering-Zeiten und die Arbeitsspeichernutzung, streamt diese Messwerte in eine benutzerdefinierte Ausgabelogdatei (logFile) und ruft nach Abschluss finish() auf. Test Lab erfasst dann die Logdatei und stellt sie Ihnen in Cloud Storage und in der Firebase-Konsole zur Verfügung.

Anwendungsfälle

Je nach verwendeter Game Engine können Sie Tests mit einer oder mehreren Schleifen implementieren. Eine Schleife ist ein vollständiger oder teilweiser Durchlauf Ihres Tests für Ihre Gaming-App. Spielschleifen können für Folgendes verwendet werden:

  • Spielen Sie ein Level Ihres Spiels so, wie es ein Endnutzer tun würde. Sie können entweder die Eingabe des Nutzers scripten, den Nutzer inaktiv lassen oder den Nutzer durch eine KI ersetzen, wenn dies in Ihrem Spiel sinnvoll ist. Wenn Sie beispielsweise eine Rennspiel-Gaming-App haben und bereits eine KI implementiert ist, können Sie einen KI-Fahrer für die Eingabe des Nutzers verantwortlich machen.
  • Führen Sie Ihr Spiel mit der höchsten Qualitätseinstellung aus, um zu sehen, ob Geräte diese unterstützen.
  • Führen Sie einen technischen Test durch (kompilieren Sie mehrere Shader, führen Sie sie aus, prüfen Sie, ob die Ausgabe wie erwartet ist usw.).

Sie können einen Spielschleifentest auf einem einzelnen Testgerät, einer Gruppe von Testgeräten oder auf Test Lab ausführen. Wir empfehlen jedoch nicht, Spielschleifen-Tests auf virtuellen Geräten auszuführen, da sie niedrigere Grafiken-Framerate als physische Geräte haben.

Hinweis

Wenn Sie einen Test implementieren möchten, müssen Sie Ihre App zuerst für Spielschleifen-Tests konfigurieren.

  1. Fügen Sie in Ihrem App-Manifest Ihrer activity einen neuen Intent-Filter hinzu:

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

    So kann Test Lab Ihr Spiel starten, indem es mit einer bestimmten Intention ausgelöst wird.

  2. Fügen Sie in Ihrem Code (wir empfehlen innerhalb der onCreate-Methodendeklaration) Folgendes hinzu:

    Kotlin

    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
    }

    So kann Ihre Aktivität den Intent prüfen, mit dem sie gestartet wird. Sie können diesen Code auch später hinzufügen, z.B. nachdem Sie Ihre Spiele-Engine geladen haben.

  3. Empfehlung: Fügen Sie am Ende des Tests Folgendes hinzu:

    Kotlin

    yourActivity.finish()

    Java

    yourActivity.finish();

    Dadurch wird Ihre App geschlossen, wenn der Spielschleife-Test abgeschlossen ist. Der Test ist darauf angewiesen, dass das UI-Framework Ihrer App den nächsten Loop startet. Wenn Sie Ihre App schließen, wird dem Framework mitgeteilt, dass der Test abgeschlossen ist.

Spielschleifentest erstellen und ausführen

Nachdem Sie Ihre App für Spielschleifen-Tests konfiguriert haben, können Sie sofort einen Test erstellen und in Ihrer Gaming-App ausführen. Sie können einen Test in Test Lab entweder über die Firebase-Konsole oder die gcloud-Befehlszeile oder auf einem lokalen Gerät mit dem Testschleifen-Manager ausführen.

Auf einem lokalen Gerät ausführen

Der Testschleifen-Manager von Test Lab ist eine Open-Source-App, mit der Sie Spielschleifen-Tests einbinden und auf Ihren lokalen Geräten ausführen können. Außerdem kann Ihr Qualitätssicherungsteam dieselben Spielschleifen auf seinen Geräten ausführen.

So führen Sie einen Test auf einem lokalen Gerät mit dem Test Loop Manager aus:

  1. Laden Sie den Test Loop Manager auf ein Smartphone oder Tablet herunter und installieren Sie ihn mit folgendem Befehl:
    adb install testloopmanager.apk
  2. Öffnen Sie auf Ihrem Smartphone oder Tablet die App Test Loop Apps. In der App wird eine Liste der Apps auf Ihrem Gerät angezeigt, die mit Game-Loops ausgeführt werden können. Wenn Ihre Gaming-App hier nicht angezeigt wird, prüfen Sie, ob Ihr Intent-Filter mit dem im ersten Schritt des Abschnitts Vorbereitung beschriebenen Filter übereinstimmt.
  3. Wählen Sie Ihre Gaming-App und dann die Anzahl der Schleifen aus, die Sie ausführen möchten. Hinweis: In diesem Schritt können Sie auch eine Teilmenge von Schleifen anstelle von nur einer Schleife ausführen. Weitere Informationen zum gleichzeitigen Ausführen mehrerer Schleifen finden Sie unter Optionale Funktionen.
  4. Klicken Sie auf Testen. Ihr Test wird sofort ausgeführt.

Laufen in Test Lab

Sie können einen Spielschleife-Test in Test Lab entweder mit der Firebase Console oder der gcloud CLI ausführen. Bevor Sie beginnen, öffnen Sie die Firebase-Konsole und erstellen Sie ein Projekt, falls Sie dies noch nicht getan haben.

Firebase-Konsole verwenden

  1. Klicken Sie in der Firebase-Konsole im linken Bereich auf Test Lab.
  2. Klicken Sie auf Ersten Test ausführen oder auf Test ausführen, wenn in Ihrem Projekt bereits ein Test ausgeführt wurde.
  3. Wählen Sie Spielschleife als Testtyp aus und klicken Sie auf Weiter.
  4. Klicken Sie auf Durchsuchen und suchen Sie nach der .apk-Datei Ihrer App. Hinweis: In diesem Schritt können Sie auch eine Teilmenge von Schleifen anstelle von nur einer Schleife ausführen. Weitere Informationen zum gleichzeitigen Ausführen mehrerer Schleifen finden Sie unter Optionale Funktionen.
  5. Klicken Sie auf Weiter.
  6. Wählen Sie die physischen Geräte aus, mit denen Sie Ihre App testen möchten.
  7. Klicken Sie auf Tests starten.

Weitere Informationen zu den ersten Schritten mit der Firebase-Konsole finden Sie unter Mit der Firebase-Konsole testen.

gcloud-Befehlszeile verwenden

  1. Laden Sie das Google Cloud SDK herunter und installieren Sie es, falls noch nicht geschehen.

  2. Melden Sie sich mit Ihrem Google-Konto in der gcloud CLI an:

    gcloud auth login

  3. Legen Sie Ihr Firebase-Projekt in gcloud fest. Dabei ist PROJECT_ID die ID Ihres Firebase-Projekts:

    gcloud config set project PROJECT_ID
    
  4. Ersten Test ausführen:

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

Weitere Informationen zu den ersten Schritten mit der gcloud CLI finden Sie unter Tests über die gcloud-Befehlszeile starten.

Optionale Funktionen

Test Lab bietet mehrere optionale Funktionen, mit denen Sie Ihre Tests weiter anpassen können. Dazu gehören die Möglichkeit, Ausgabedaten zu schreiben, die Unterstützung mehrerer Game-Loops und Labels für zugehörige Loops.

Ausgabedaten schreiben

Wenn Test Lab Ihr Spiel startet, wird eine URL angegeben, die auf eine lokale Ergebnisdatei auf dem Testgerät verweist, auf die mit launchIntent.getData() zugegriffen werden kann. Ihr Spiel kann während des Testlaufs Testergebnisse, Leistungsmesswerte und Logs (logFile) direkt an diesen Speicherort schreiben.

Sie können beliebige Inhalte in logFile schreiben, z. B. Nur-Text, CSV-Daten, Frame-Rendering-Zeiten oder benutzerdefinierte Diagnoseberichte. Für die Inhalte, die Sie schreiben, gibt es keine Einschränkungen oder Formatierungsanforderungen. Die Datei wird erfasst, wenn Ihr Test abgeschlossen ist, und zusammen mit Ihren anderen Testartefakten in Ihren Cloud Storage-Bucket hochgeladen.

Test Lab folgt den etablierten Best Practices für das Teilen einer Datei zwischen Apps, die unter Datei freigeben beschrieben werden. In der onCreate()-Methode Ihrer Aktivität, in der sich Ihr Intent befindet, können Sie Ihre Datenausgabedatei mit dem folgenden Code abrufen und prüfen:

Kotlin

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());
    // ...
}

Wenn Sie von der C++-Seite Ihrer Spiele-App in die Datei schreiben möchten, können Sie den Dateideskriptor anstelle des Dateipfads übergeben:

Kotlin

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

Beispiel für Ausgabedatei

Für Test Lab ist zwar kein bestimmtes Format für logFile erforderlich, aber wenn Sie die Ausgabe als JSON-Datei strukturieren, die dem Schema unten entspricht, kann die Firebase-Konsole (https://console.firebase.google.com/project/_/testlab) Zusammenfassungsstatistiken für Ihren Game-Loop-Test parsen und anzeigen.

Wichtige Details zu diesem Beispiel:

  • Wer stellt die Daten bereit? Sie (der Testentwickler) sind dafür verantwortlich, alle Messwerte aus Ihrem Spielcode zu berechnen und in diese Datei zu schreiben. Test Lab erfasst oder generiert diese Datenpunkte nicht automatisch für Sie.
  • Benutzerdefinierte Felder hinzufügen:Bereiche, die mit /.../ gekennzeichnet sind, geben an, wo Sie beliebige benutzerdefinierte Schlüssel/Wert-Paare hinzufügen können, z. B. "rendered_vertices": 12000 oder "ai_error_count": 0. Sie können Ihrer Ausgabe beim Schreiben der Datei aus Ihrer App eine beliebige gültige JSON-Eigenschaft hinzufügen, solange die Feldnamen nicht mit Schemafeldern wie name oder start_timestamp in Konflikt stehen.
  • Ausgabedatei suchen:Nach Abschluss des Tests wird die Rohausgabedatei im Artefaktverzeichnis des Testlaufs im Cloud Storage-Ergebnis-Bucket (GCS) Ihres Projekts gespeichert und kann dort heruntergeladen werden. Sie können die geparste Ausgabe auch auf der Seite Test Lab der Firebase-Konsole ansehen und prüfen.

Im Folgenden sehen Sie ein Beispiel für eine strukturierte JSON-Ausgabedatei:

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

Mehrere Spielschleifen

Es kann sinnvoll sein, mehrere Spielschleifen in Ihrer App auszuführen. Eine Schleife ist ein vollständiger Durchlauf Ihrer Spiele-App von Anfang bis Ende. Wenn Ihr Spiel beispielsweise mehrere Level hat, sollten Sie für jedes Level einen eigenen Game-Loop verwenden, anstatt einen Loop, der alle Level durchläuft. Wenn Ihre App beispielsweise auf Level 32 abstürzt, können Sie diesen Game-Loop direkt starten, um den Absturz zu reproduzieren und Fehlerkorrekturen zu testen.

So ermöglichen Sie, dass Ihre App mehrere Schleifen gleichzeitig ausführt:

  • Wenn Sie einen Test mit dem Test Loop Manager durchführen:

    1. Fügen Sie dem Manifest Ihrer App innerhalb des <application>-Elements die folgende Zeile hinzu:

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

      Dieser Start-Intent enthält die Zielgruppe als Ganzzahlparameter. Im Feld android:value können Sie eine Ganzzahl von 1 bis 1024 angeben (die maximale Anzahl von Schleifen, die für einen einzelnen Test zulässig sind). Schleifen werden ab 1 und nicht ab 0 indexiert.

    2. In der Test Loop Manager App wird ein Auswahlbildschirm angezeigt, auf dem Sie die Schleifen auswählen können, die Sie ausführen möchten. Wenn Sie mehrere Schleifen auswählen, wird jede Schleife nacheinander gestartet, nachdem die vorherige Schleife abgeschlossen ist.

  • Wenn Sie einen Test mit der Firebase-Konsole ausführen, geben Sie im Feld Szenarien eine Liste oder einen Bereich von Schleifennummern ein.

  • Wenn Sie einen Test mit der gcloud CLI ausführen, geben Sie eine Liste von Schleifennummern mit dem Flag --scenario-numbers an. Beispiel: --scenario-numbers=1,3,5 führt die Schleifen 1, 3 und 5 aus.

  • Wenn Sie C++ schreiben und das Verhalten Ihrer Schleife ändern möchten, übergeben Sie den folgenden Extra an Ihren nativen C++-Code:

    Kotlin

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

    Java

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

    Sie können das Verhalten Ihrer Schleife jetzt basierend auf dem resultierenden int-Wert ändern.

Spielschleifen labeln

Wenn Sie Ihre Spielschleifen mit einem oder mehreren Szenariolabels kennzeichnen, können Sie und Ihr QA-Team ganz einfach eine Reihe von zugehörigen Spielschleifen (z.B. „alle Kompatibilitätsspielschleifen“) starten und in einer einzigen Matrix testen. Sie können eigene Labels erstellen oder die vordefinierten Labels von Test Lab verwenden:

  • com.google.test.loops.player_experience: For-Schleifen, die verwendet werden, um die Erfahrung eines echten Nutzers beim Spielen des Spiels zu reproduzieren. Ziel der Tests mit diesen Schleifen ist es, Probleme zu finden, die bei einem echten Nutzer beim Spielen des Spiels auftreten würden.
  • com.google.test.loops.gpu_compatibility: For-Schleifen, die zum Testen von GPU-bezogenen Problemen verwendet werden. Ziel der Tests mit diesen Schleifen ist es, GPU-Code auszuführen, der in der Produktion möglicherweise nicht richtig ausgeführt wird, um Probleme mit Hardware und Treibern aufzudecken.
  • com.google.test.loops.compatibility: For-Schleifen, die zum Testen einer Vielzahl von Kompatibilitätsproblemen verwendet werden, einschließlich E/A- und OpenSSL-Problemen.
  • com.google.test.loops.performance: For-Schleifen zum Testen der Leistung des Geräts. Ein Spiel kann beispielsweise mit den komplexesten Grafikeinstellungen ausgeführt werden, um zu sehen, wie sich ein neues Gerät verhält.

So ermöglichen Sie, dass Ihre App Schleifen mit demselben Label ausführt:

  • Wenn Sie einen Test mit dem Test Loop Manager durchführen:

    1. Fügen Sie im Manifest Ihrer App die folgende Metadatenzeile hinzu und ersetzen Sie LABEL_NAME durch ein Label Ihrer Wahl:

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

      Im Feld android:value können Sie einen Bereich oder eine Menge von Ganzzahlen zwischen 1 und 1024 (die maximal zulässige Anzahl von Schleifen für einen einzelnen Test) angeben, die die Schleifen darstellen, die Sie labeln möchten. Schleifen werden ab 1 und nicht ab 0 indexiert. Beispiel: android:value="1,3-5" wendet LABEL_NAME auf die Schleifen 1, 3, 4 und 5 an.

    2. Geben Sie in der Test Loop Manager App ein oder mehrere Labels in das Feld Labels ein.

  • Wenn Sie einen Test mit der Firebase-Konsole ausführen, geben Sie ein oder mehrere Labels in das Feld Labels ein.

  • Wenn Sie einen Test mit der gcloud CLI ausführen, geben Sie ein oder mehrere Szenariolabels mit dem Flag --scenario-labels an (z.B. --scenario-labels=performance,gpu).

Support für die App-Lizenzierung

Test Lab unterstützt Apps, die den von Google Play angebotenen Dienst App-Lizenzierung verwenden. Damit die Lizenzierung beim Testen Ihrer App mit Test Lab erfolgreich geprüft werden kann, müssen Sie Ihre App im Play Store im Produktionschannel veröffentlichen. Wenn Sie Ihre App im Alpha- oder Betakanal mit Test Lab testen möchten, entfernen Sie die Lizenzprüfung, bevor Sie Ihre App in Test Lab hochladen.

Bekannte Probleme

Für Spielschleifentests in Test Lab gelten die folgenden bekannten Probleme:

  • Für einige Abstürze sind keine Backtraces verfügbar. Beispielsweise kann bei einigen Release-Builds die Ausgabe des debuggerd-Prozesses mit prctl(PR_SET_DUMPABLE, 0) unterdrückt werden. Weitere Informationen finden Sie unter debuggerd.
  • API-Level 19 wird derzeit aufgrund von Dateiberechtigungsfehlern nicht unterstützt.