Pierwsze kroki z testami pętli gry

Automatyzacja testowania gier może być trudna, gdy gry mobilne są tworzone na różnych platformach interfejsu. Testy pętli gry umożliwiają integrację testów natywnych z Test Lab i łatwe uruchamianie ich na wybranych urządzeniach. Test pętli gry uruchamia test w grze mobilnej, symulując działania prawdziwego gracza. Z tego przewodnika dowiesz się, jak przeprowadzić test pętli gry, a następnie wyświetlić wyniki testu i zarządzać nimi w konsoli Firebase.

Czym jest test pętli gry?

Gry mobilne są renderowane w różnych platformach i silnikach interfejsu, takich jak Unity, Unreal czy kod C++ OpenGL/Vulkan, dlatego standardowe narzędzia do automatyzacji nie mogą sprawdzać elementów interfejsu ani wchodzić z nimi w interakcje. Test pętli gry umożliwia integrację testów natywnego silnika z Test Lab przez uruchomienie gry z intencją zawierającą określony numer scenariusza. Ten numer scenariusza powoduje, że aplikacja uruchamia wstępnie zaprogramowaną logikę, symulacje AI lub testy wydajności bezpośrednio w silniku gry.

Po uruchomieniu Test Lab nie wchodzi w interakcję z interfejsem gry. Zamiast tego Test Lab działa jako środowisko testowe i transport: uruchamia określony scenariusz, monitoruje awarie i przekroczenia limitu czasu oraz zbiera niestandardowe dzienniki wyników, gdy aplikacja zakończy działanie pętli.

Czym pętle gry różnią się od testów z instrumentacją

  • Testy z instrumentacją (takie jak Espresso czy UI Automator) korzystają z zewnętrznych platform do obsługi interakcji z interfejsem, klikania przycisków i potwierdzania stanu aplikacji w hierarchii widoków Androida spoza aplikacji.
  • Testy pętli gry przekazują logikę testową do aplikacji. Aplikacja uruchamia własną wewnętrzną pętlę testową lub symulację bez interakcji z zewnętrznym interfejsem, a Test Lab uruchamia scenariusz i zbiera dane wyjściowe testu.

Przykłady

Załóżmy, że chcesz sprawdzić, czy gra utrzymuje co najmniej 60 klatek na sekundę na różnych urządzeniach fizycznych. Możesz zaimplementować scenariusz 1 w kodzie gry, aby wczytać najbardziej złożony wizualnie poziom i pozwolić graczowi AI lub automatycznemu skryptowi grać przez 2 minuty.

Gdy Test Lab aktywuje scenariusz 1, gra rozpoczyna rozgrywkę AI, monitoruje czasy renderowania klatek i wykorzystanie pamięci, przesyła te dane do niestandardowego pliku dziennika wyjściowego (logFile) i po zakończeniu wywołuje finish(). Test Lab przechwytuje plik dziennika i udostępnia go w Cloud Storage oraz konsoli Firebase.

Przypadki użycia

W zależności od silnika gry możesz wdrożyć testy z jedną pętlą lub wieloma pętlami. Pętla to pełne lub częściowe uruchomienie testu w grze mobilnej. Pętli gry można używać do:

  • Uruchom poziom gry w taki sam sposób, jak zrobiłby to użytkownik. Możesz zaprogramować dane wejściowe użytkownika, pozostawić użytkownika bezczynnego lub zastąpić go sztuczną inteligencją, jeśli ma to sens w Twojej grze (np. jeśli masz grę wyścigową i masz już zaimplementowaną sztuczną inteligencję, możesz powierzyć jej sterowanie pojazdem).
  • Uruchom grę z najwyższymi ustawieniami jakości, aby sprawdzić, czy urządzenia ją obsługują.
  • przeprowadzić test techniczny (skompilować wiele obiektów cieniujących, wykonać je, sprawdzić, czy dane wyjściowe są zgodne z oczekiwaniami itp.);

Test pętli gry możesz przeprowadzić na jednym urządzeniu testowym, zestawie urządzeń testowych lub na platformie Test Lab. Nie zalecamy jednak przeprowadzania testów pętli gry na urządzeniach wirtualnych, ponieważ mają one mniejszą liczbę klatek grafiki niż urządzenia fizyczne.

Zanim zaczniesz

Aby przeprowadzić test, musisz najpierw skonfigurować aplikację pod kątem testów pętli gry.

  1. W pliku manifestu aplikacji dodaj do aktywności nowy filtr intencji:

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

    Dzięki temu Test Lab może uruchomić grę, wywołując ją za pomocą określonej intencji.

  2. W kodzie (zalecamy w deklaracji metody onCreate) dodaj:

    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
    }

    Dzięki temu aktywność może sprawdzić intencję, która ją uruchamia. Możesz też dodać ten kod później, jeśli wolisz (np. po początkowym załadowaniu silnika gry).

  3. Zalecane: na końcu testu dodaj:

    Kotlin

    yourActivity.finish()

    Java

    yourActivity.finish();

    Dzięki temu aplikacja zostanie zamknięta po zakończeniu testu pętli gry. Test opiera się na platformie interfejsu aplikacji, aby rozpocząć następną pętlę, a zamknięcie aplikacji informuje go, że test został zakończony.

Tworzenie i przeprowadzanie testu pętli gry

Po skonfigurowaniu aplikacji do testów pętli gry możesz od razu utworzyć test i uruchomić go w grze mobilnej. Możesz uruchomić test w Test Lab za pomocą konsoli Firebase lub interfejsu wiersza poleceń (CLI) gcloud albo na urządzeniu lokalnym za pomocą Test Loop Managera.

Uruchamianie na urządzeniu lokalnym

Test Loop Manager w Test Lab to aplikacja open source, która pomaga integrować testy pętli gry i uruchamiać je na urządzeniach lokalnych. Dzięki temu zespół ds. zapewniania jakości może uruchamiać te same pętle gry na swoich urządzeniach.

Aby przeprowadzić test na urządzeniu lokalnym za pomocą aplikacji Test Loop Manager:

  1. Pobierz Test Loop Managera na telefon lub tablet i zainstaluj go, uruchamiając:
    adb install testloopmanager.apk
  2. Na urządzeniu otwórz aplikację Test Loop Apps na telefonie lub tablecie. Aplikacja wyświetli listę aplikacji na urządzeniu, które można uruchomić z pętlami gry. Jeśli nie widzisz tu swojej gry mobilnej, upewnij się, że filtr intencji jest zgodny z filtrem opisanym w pierwszym kroku w sekcji Zanim zaczniesz.
  3. Wybierz grę mobilną, a następnie liczbę pętli, które chcesz uruchomić. Uwaga: na tym etapie możesz wybrać podzbiór pętli, a nie tylko jedną pętlę. Więcej informacji o uruchamianiu wielu pętli jednocześnie znajdziesz w sekcji Funkcje opcjonalne.
  4. Kliknij Uruchom test. Test rozpocznie się natychmiast.

Bieg w Test Lab

Test pętli gry możesz uruchomić w Test Lab za pomocą konsoli Firebase lub gcloud CLI. Zanim zaczniesz, otwórz konsolę Firebase i utwórz projekt.

Korzystanie z konsoli Firebase

  1. W konsoli Firebase kliknij Test Lab w panelu po lewej stronie.
  2. Kliknij Run Your First Test (Uruchom pierwszy test) lub Run a Test (Uruchom test), jeśli w projekcie był już wcześniej uruchamiany test.
  3. Wybierz Pętla gry jako typ testu, a następnie kliknij Dalej.
  4. Kliknij Przeglądaj, a następnie znajdź plik .apk aplikacji. Uwaga: na tym etapie możesz wybrać podzbiór pętli, a nie tylko jedną pętlę. Więcej informacji o uruchamianiu wielu pętli jednocześnie znajdziesz w sekcji Funkcje opcjonalne.
  5. Kliknij Dalej.
  6. Wybierz urządzenia fizyczne, na których chcesz przetestować aplikację.
  7. Kliknij Rozpocznij testy.

Więcej informacji o rozpoczynaniu pracy z konsolą Firebase znajdziesz w artykule Rozpoczynanie testowania w konsoli Firebase.

Korzystanie z interfejsu wiersza poleceń gcloud (CLI)

  1. Pobierz i zainstaluj Google Cloud SDK, jeśli jeszcze nie masz tego pakietu.

  2. Zaloguj się w gcloud CLI za pomocą konta Google:

    gcloud auth login

  3. Ustaw projekt w Firebase w gcloud, gdzie PROJECT_ID to identyfikator projektu w Firebase:

    gcloud config set project PROJECT_ID
    
  4. Przeprowadź pierwszy test:

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

Więcej informacji o rozpoczynaniu pracy z gcloud CLI znajdziesz w artykule Rozpoczynanie testowania z poziomu wiersza poleceń gcloud.

Funkcje opcjonalne

Test Lab oferuje kilka opcjonalnych funkcji, które pozwalają na dalsze dostosowywanie testów, w tym możliwość zapisywania danych wyjściowych, obsługę wielu pętli gry i etykiety powiązanych pętli.

Zapisywanie danych wyjściowych

Gdy Test Lab uruchamia grę, określa adres URL wskazujący lokalny plik wyników na urządzeniu testowym, który jest dostępny za pomocą launchIntent.getData(). Podczas testu gra może zapisywać wyniki testów, wskaźniki skuteczności i logi (logFile) bezpośrednio w tej lokalizacji.

W logFile możesz zapisać dowolne treści, takie jak zwykły tekst, dane CSV, czasy renderowania klatek czy niestandardowe raporty diagnostyczne. Nie ma żadnych ograniczeń ani wymagań dotyczących formatowania treści. Plik jest przechwytywany po zakończeniu testu i przesyłany do zasobnika Cloud Storage wraz z innymi artefaktami testu.

Test Lab postępuje zgodnie ze sprawdzonymi metodami udostępniania plików między aplikacjami opisanymi w artykule Udostępnianie pliku. W metodzie onCreate() aktywności, w której znajduje się intencja, możesz pobrać i sprawdzić plik wyjściowy danych, uruchamiając ten kod:

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

Jeśli chcesz zapisywać w pliku z poziomu kodu C++ swojej gry mobilnej, możesz przekazać deskryptor pliku zamiast ścieżki do pliku:

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

Przykładowy plik wyjściowy

Chociaż Test Lab nie wymaga określonego formatu dla logFile, uporządkowanie danych wyjściowych w formacie JSON zgodnym z poniższym schematem umożliwia konsoli Firebase (https://console.firebase.google.com/project/_/testlab) analizowanie i wyświetlanie podsumowania danych dotyczących testu pętli gry.

Najważniejsze informacje o tym przykładzie:

  • Kto dostarcza dane: Ty (deweloper testu) odpowiadasz za obliczanie i zapisywanie wszystkich danych w tym pliku z kodu gry. Test Lab nie zbiera ani nie generuje automatycznie tych punktów danych.
  • Dodawanie pól niestandardowych: obszary oznaczone jako /.../ wskazują, gdzie można dodać dowolne niestandardowe pary klucz-wartość (np. "rendered_vertices": 12000 lub "ai_error_count": 0). Podczas zapisywania pliku z aplikacji możesz dodać do danych wyjściowych dowolną prawidłową właściwość JSON, o ile nazwy pól nie kolidują z polami schematu, takimi jak name lub start_timestamp.
  • Gdzie znaleźć plik wyjściowy: po zakończeniu testu nieprzetworzony plik wyjściowy jest przechowywany i można go pobrać z zasobnika wyników Cloud Storage (GCS) projektu w katalogu artefaktów uruchomienia testu. Przeanalizowane dane wyjściowe możesz też wyświetlić i sprawdzić na stronie Test Lab w konsoli Firebase.

Oto przykładowy plik wyjściowy JSON o uporządkowanej strukturze:

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

Wiele pętli gry

Możesz uruchomić w aplikacji kilka pętli gry. Pętla to pełne przejście gry od początku do końca. Jeśli na przykład gra ma kilka poziomów, możesz utworzyć pętlę gry, która uruchamia każdy poziom, zamiast jednej pętli, która przechodzi przez wszystkie poziomy. Dzięki temu, jeśli aplikacja ulegnie awarii na poziomie 32, możesz bezpośrednio uruchomić tę pętlę gry, aby odtworzyć awarię i przetestować poprawki błędów.

Aby umożliwić aplikacji uruchamianie wielu pętli jednocześnie:

  • Jeśli przeprowadzasz test za pomocą aplikacji Test Loop Manager:

    1. Dodaj ten wiersz do pliku manifestu aplikacji w elemencie <application>:

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

      Ta intencja uruchomienia zawiera pętlę docelową jako parametr liczby całkowitej. W polu android:value możesz podać liczbę całkowitą od 1 do 1024 (maksymalna liczba pętli dozwolona w jednym teście). Pamiętaj, że pętle są indeksowane od 1, a nie od 0.

    2. W aplikacji Test Loop Manager pojawi się ekran wyboru, na którym możesz wybrać pętle do uruchomienia. Jeśli wybierzesz kilka pętli, każda z nich będzie uruchamiana po zakończeniu poprzedniej.

  • Jeśli przeprowadzasz test za pomocą konsoli Firebase, w polu Scenariusze wpisz listę lub zakres numerów pętli.

  • Jeśli przeprowadzasz test za pomocą gcloud CLI, określ listę numerów pętli, używając flagi --scenario-numbers. Na przykład --scenario-numbers=1,3,5 uruchamia pętle 1, 3 i 5.

  • Jeśli piszesz w C++ i chcesz zmienić zachowanie pętli, przekaż do kodu natywnego C++ ten dodatkowy element:

    Kotlin

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

    Java

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

    Możesz teraz zmienić zachowanie pętli na podstawie wynikowej wartości int.

Etykietowanie pętli gry

Gdy oznaczysz pętle gry co najmniej 1 etykietą scenariusza, Ty i Twój zespół ds.kontroli jakości możecie łatwo uruchomić zestaw powiązanych pętli gry (np. „wszystkie pętle gry dotyczące zgodności”) i przetestować je w jednej macierzy. Możesz utworzyć własne etykiety lub użyć etykiet wstępnie zdefiniowanych przez Test Lab:

  • com.google.test.loops.player_experience: pętle for używane do odtworzenia wrażeń prawdziwego użytkownika podczas grania. Celem testowania za pomocą tych pętli jest znalezienie problemów, które mogą wystąpić podczas rozgrywki.
  • com.google.test.loops.gpu_compatibility: pętle for używane do testowania problemów związanych z GPU. Celem testowania za pomocą tych pętli jest wykonanie kodu GPU, który może nie działać prawidłowo w środowisku produkcyjnym, aby wykryć problemy ze sprzętem i sterownikami.
  • com.google.test.loops.compatibility: pętle for używane do testowania szerokiego zakresu problemów ze zgodnością, w tym problemów z wejściem/wyjściem i OpenSSL.
  • com.google.test.loops.performance: pętle for używane do testowania wydajności urządzenia. Na przykład gra może działać przy najbardziej złożonych ustawieniach grafiki, aby sprawdzić, jak zachowuje się nowe urządzenie.

Aby umożliwić aplikacji uruchamianie pętli z tą samą etykietą:

  • Jeśli przeprowadzasz test za pomocą aplikacji Test Loop Manager:

    1. W pliku manifestu aplikacji dodaj następujący wiersz metadanych i zastąp LABEL_NAME wybraną etykietą:

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

      W polu android:value możesz określić zakres lub zbiór liczb całkowitych od 1 do 1024 (maksymalna liczba pętli dozwolona w jednym teście), które reprezentują pętle, które chcesz oznaczyć etykietą. Pamiętaj, że pętle są indeksowane od 1, a nie od 0. Na przykład android:value="1,3-5" stosuje LABEL_NAME do pętli 1, 3, 4 i 5.

    2. W aplikacji Test Loop Manager wpisz co najmniej 1 etykietę w polu Etykiety.

  • Jeśli przeprowadzasz test za pomocą konsoli Firebase, wpisz co najmniej 1 etykietę w polu Etykiety.

  • Jeśli przeprowadzasz test za pomocą gcloud CLI, określ co najmniej 1 etykietę scenariusza, używając flagi --scenario-labels (np. --scenario-labels=performance,gpu).

Pomoc dotycząca licencjonowania aplikacji

Test Lab obsługuje aplikacje, które korzystają z usługi licencjonowania aplikacji oferowanej przez Google Play. Aby pomyślnie sprawdzić licencjonowanie podczas testowania aplikacji za pomocą Test Lab, musisz opublikować aplikację na kanale produkcyjnym w Sklepie Play. Aby przetestować aplikację w wersji alfa lub beta za pomocą Test Lab, usuń sprawdzanie licencji przed przesłaniem aplikacji do Test Lab.

Znane problemy

Testy pętli gry w Test Lab mają te znane problemy:

  • Niektóre awarie nie obsługują śladów stosu. Na przykład niektóre kompilacje do publikacji mogą pomijać dane wyjściowe procesu debuggerd za pomocą prctl(PR_SET_DUMPABLE, 0). Więcej informacji znajdziesz w artykule debuggerd.
  • Poziom interfejsu API 19 nie jest obecnie obsługiwany z powodu błędów uprawnień do plików.