Pierwsze kroki z testami pętli gry na iOS

Dzięki testom pętli gry możesz pisać testy natywne dla silnika gry, a następnie uruchamiać je w Test Lab na wybranych urządzeniach. Dzięki temu nie musisz się martwić pisaniem kodu dla różnych interfejsów użytkownika ani platform testowych. Test pętli gry symuluje działania prawdziwego gracza. Uruchomienie go na Test Lab to szybki i skalowalny sposób na sprawdzenie, czy gra działa prawidłowo w przypadku użytkowników.

Na tej stronie dowiesz się, jak przeprowadzić test pętli gry, a potem wyświetlić wyniki testu i zarządzać nimi na stronie Test Lab w konsoli Firebase. Możesz też dostosować testy za pomocą funkcji opcjonalnych, takich jak pisanie niestandardowych wyników testów czy wcześniejsze zakończenie testu.

Co to jest test pętli gry?

Pętla to pełne lub częściowe przeprowadzenie testu w aplikacji do gier. Test pętli gry możesz przeprowadzić lokalnie na symulatorze lub na zestawie urządzeń w Test Lab. Testy pętli gry mogą służyć do:

  • Przejdź grę tak, jak zrobiłby to użytkownik. Możesz zaprogramować dane wejściowe użytkownika, pozwolić mu na bezczynność lub zastąpić go AI (np. jeśli w grze wyścigowej zaimplementowano AI, możesz powierzyć kierowanie pojazdem sterowanym przez użytkownika kierowcy AI).

  • Uruchom grę w najwyższej jakości, aby sprawdzić, które urządzenia ją obsługują.

  • Przeprowadź test techniczny, np. skompiluj wiele shaderów, wykonaj je i sprawdź, czy dane wyjściowe są zgodne z oczekiwaniami.

Krok 1. Zarejestruj niestandardowy schemat URI adresu URL Test Lab

Najpierw musisz zarejestrować w aplikacji niestandardowy schemat adresu URL Firebase Test Lab:

  1. W Xcode wybierz cel projektu.

  2. Kliknij kartę Informacje, a następnie dodaj nowy typ adresu URL.

  3. W polu Schematy URL wpisz firebase-game-loop. Możesz też zarejestrować niestandardowy schemat adresu URL, dodając go do pliku konfiguracji projektuInfo.plist w dowolnym miejscu w tagu <dict>:

    <key>CFBundleURLTypes</key>
     <array>
         <dict>
             <key>CFBundleURLName</key>
             <string></string>
             <key>CFBundleTypeRole</key>
             <string>Editor</string>
             <key>CFBundleURLSchemes</key>
             <array>
                 <string>firebase-game-loop</string>
             </array>
         </dict>
     </array>
    

Aplikacja jest teraz skonfigurowana do przeprowadzenia testu z użyciem Test Lab.

Krok 2 (opcjonalnie). Skonfiguruj aplikację tak, aby uruchamiała wiele pętli

Jeśli Twoja aplikacja ma zarejestrowanych kilka niestandardowych schematów adresów URL i planujesz uruchomić w teście kilka pętli (czyli scenariuszy), musisz określić, które pętle chcesz uruchomić w aplikacji w momencie jej uruchomienia.

W delegacie aplikacji zastąp metodę application(_:open:options:):

Swift

func application(_app: UIApplication,
                 open url: URL
                 options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!
    if components.scheme == "firebase-game-loop" {
        // ...Enter Game Loop Test logic to override application(_:open:options:).
    }
    return true
}

Objective-C

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary &lt;UIApplicationOpenURLOptionsKey, id&gt; *)options {
  if ([url.scheme isEqualToString:(@"firebase-game-loop")]) {
      // ...Enter Game Loop Test logic to override application(_:open:options:).
  }
}

Gdy w teście uruchamiasz wiele pętli, bieżąca pętla jest przekazywana jako parametr do adresu URL używanego do uruchamiania aplikacji. Możesz też uzyskać numer bieżącej pętli, analizując obiekt URLComponents używany do pobierania niestandardowego schematu adresu URL:

Swift

if components.scheme == "firebase-game-loop" {
    // Iterate over all parameters and find the one with the key "scenario".
    let scenarioNum = Int(components.queryItems!.first(where: { $0.name == "scenario" })!.value!)!
    // ...Write logic specific to the current loop (scenarioNum).
}

Objective-C

if ([url.scheme isEqualToString:(@"firebase-game-loop")]) {
    // Launch the app as part of a game loop.
    NSURLComponents *components = [NSURLComponents componentsWithURL:url
                                             resolvingAgainstBaseURL:YES];
    for (NSURLQueryItem *item in [components queryItems]) {
        if ([item.name isEqualToString:@"scenario"]) {
            NSInteger scenarioNum = [item.value integerValue];
            // ...Write logic specific to the current loop (scenarioNum).
        }
    }
}

Krok 3. Utwórz i przeprowadź test

Po zarejestrowaniu niestandardowego schematu adresu URL Test Lab możesz uruchomić test w Firebase konsoli lub za pomocą interfejsu wiersza poleceń gcloud w wersji beta. Jeśli nie masz jeszcze pliku IPA aplikacji, wygeneruj go (będzie on potrzebny później).

Uruchamianie testu w konsoli Firebase

  1. Jeśli jeszcze tego nie zrobiono, otwórz Firebasekonsolę i utwórz projekt.

  2. Na stronie Test Lab w konsoli Firebase kliknij Uruchom pierwszy test > Uruchom pętlę gry na iOS.

  3. W sekcji Prześlij aplikację kliknij Przeglądaj, a następnie wybierz plik IPA aplikacji (jeśli jeszcze tego nie zrobisz, wygeneruj plik IPA dla swojej aplikacji).

  4. Opcjonalnie: jeśli chcesz uruchomić kilka pętli (czyli scenariuszy) naraz lub wybrać konkretne pętle do uruchomienia, wpisz numery pętli w polu Scenariusze.

    Na przykład po wpisaniu „1–3, 5” Test Lab odtworzy pętle 1, 2, 3 i 5. Domyślnie (jeśli nie wpiszesz niczego w polu Scenariusze)Test Lab uruchamia tylko pętlę 1.

  5. W sekcji Urządzenia wybierz co najmniej 1 urządzenie fizyczne, na którym chcesz przetestować aplikację, a następnie kliknij Rozpocznij testy.

Uruchamianie testu za pomocą interfejsu wiersza poleceń gcloud w wersji beta

  1. Jeśli jeszcze tego nie zrobiono, skonfiguruj lokalne środowisko pakietu SDK gcloud, a następnie zainstaluj komponent gcloud w wersji beta.

  2. Uruchom polecenie gcloud beta firebase test ios run i skonfiguruj uruchomienie za pomocą tych flag:

Flagi testów pętli gry
--type

Wymagany: określa typ testu na iOS, który chcesz przeprowadzić. Możesz wpisać typy testów xctest (domyślny) lub game-loop.

--app

Wymagany: ścieżka bezwzględna (Google Cloud Storage lub system plików) do pliku IPA aplikacji. Ten flag jest ważny tylko podczas przeprowadzania testów pętli gry.

--scenario-numbers

Pętle (czyli scenariusze), które chcesz uruchomić w aplikacji. Możesz wpisać jedną pętlę, listę pętli lub zakres pętli. Domyślna liczba pętli to 1.

Na przykład --scenario-numbers=1-3,5 obejmuje pętle 1, 2, 3 i 5.

--device-model

Urządzenie fizyczne, na którym chcesz przeprowadzić test (sprawdź, które dostępne urządzenia możesz wykorzystać).

--timeout

Maksymalny czas trwania testu. Możesz wpisać liczbę całkowitą, która będzie oznaczać czas trwania w sekundach, lub liczbę całkowitą i wyliczenie, które będą oznaczać czas trwania w dłuższej jednostce czasu.

Przykład:

  • --timeout=200 wymusza zakończenie testu po 200 sekundach.
  • --timeout=1h wymusza zakończenie testu po upływie godziny.

Na przykład to polecenie przeprowadza test pętli gry, który wykonuje pętle 1, 4, 6, 7 i 8 na iPhonie 8 Plus:

gcloud beta firebase test ios run
 --type game-loop --app path/to/my/App.ipa --scenario-numbers 1,4,6-8
 --device-model=iphone8plus

Więcej informacji o interfejsie wiersza poleceń gcloud znajdziesz w dokumentacji.

Lokalne uruchamianie testu

Aby uruchomić test lokalnie, wczytaj aplikację do gier w symulatorze i uruchom:

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
  • Identyfikator UDID symulatora znajdziesz, uruchamiając polecenie instruments -s devices.

  • Jeśli działa tylko jeden symulator, zamiast SIMULATOR_UDID wpisz specjalny ciąg znaków "booted".

Jeśli test zawiera kilka pętli, możesz określić, którą z nich chcesz uruchomić, przekazując numer pętli do flagi scenario. Pamiętaj, że podczas testowania lokalnego możesz uruchomić tylko jedną pętlę naraz. Jeśli np. chcesz uruchomić pętle 1, 2 i 5, musisz uruchomić osobne polecenie dla każdej pętli:

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=1
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=2
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=5

Wcześniejsze zakończenie testu

Domyślnie test pętli gry jest uruchamiany do momentu osiągnięcia limitu czasu 5 minut, nawet jeśli wszystkie pętle zostały już wykonane. Po osiągnięciu limitu czasu test kończy się i anuluje wszystkie oczekujące pętle. Możesz przyspieszyć test lub zakończyć go wcześniej, wywołując w pliku AppDelegate aplikacji niestandardowy schemat adresu URL Test Labfirebase-game-loop-complete. Przykład:

Swift

/// End the loop by calling our custom url scheme.
func finishLoop() {
    let url = URL(string: "firebase-game-loop-complete://")!
    UIApplication.shared.open(url)
}

Objective-C

- (void)finishLoop {
  UIApplication *app = [UIApplication sharedApplication];
  [app openURL:[NSURL URLWithString:@"firebase-game-loop-complete://"]
      options:@{}
completionHandler:^(BOOL success) {}];
}

Test pętli gry kończy bieżącą pętlę i wykonuje następną. Gdy nie ma już więcej pętli do uruchomienia, test się kończy.

Zapisywanie niestandardowych wyników testów

Możesz skonfigurować test pętli gry tak, aby zapisywał niestandardowe wyniki testu w systemie plików urządzenia. Dzięki temu po rozpoczęciu testu Test Labzapisuje pliki wyników w katalogu GameLoopsResults na urządzeniu testowym (który musisz utworzyć samodzielnie). Po zakończeniu testu Test Lab przenosi wszystkie pliki z katalogu GameLoopResults do zasobnika projektu. Podczas konfigurowania testu pamiętaj o tych kwestiach:

  • Wszystkie pliki wyników są przesyłane niezależnie od typu, rozmiaru i liczby.

  • Test Lab nie przetwarza wyników testu, dopóki nie zostaną wykonane wszystkie pętle w teście. Jeśli test zawiera wiele pętli, które zapisują dane wyjściowe, dopisz je do unikalnego pliku wyników lub utwórz plik wyników dla każdej pętli. W ten sposób unikniesz zastąpienia wyników z poprzedniej pętli.

Aby skonfigurować test w celu zapisywania niestandardowych wyników testu:

  1. W katalogu Documents aplikacji utwórz katalog o nazwie GameLoopResults.

  2. W dowolnym miejscu w kodzie aplikacji (np. w delegacie aplikacji) dodaj ten kod:

    Swift

    /// Write to a results file.
    func writeResults() {
      let text = "Greetings from game loops!"
      let fileName = "results.txt"
      let fileManager = FileManager.default
      do {
    
      let docs = try fileManager.url(for: .documentDirectory,
                                     in: .userDomainMask,
                                     appropriateFor: nil,
                                     create: true)
      let resultsDir = docs.appendingPathComponent("GameLoopResults")
      try fileManager.createDirectory(
          at: resultsDir,
          withIntermediateDirectories: true,
          attributes: nil)
      let fileURL = resultsDir.appendingPathComponent(fileName)
      try text.write(to: fileURL, atomically: false, encoding: .utf8)
      } catch {
        // ...Handle error writing to file.
      }
    }
    

    Objective-C

    /// Write to a results file.
    - (void)writeResults:(NSString *)message {
        // Locate and create the results directory (if it doesn't exist already).
        NSFileManager *manager = [NSFileManager defaultManager];
        NSURL* url = [[manager URLsForDirectory:NSDocumentDirectory
                                      inDomains:NSUserDomainMask] lastObject];
        NSURL* resultsDir = [url URLByAppendingPathComponent:@"GameLoopResults"
                                                 isDirectory:YES];
        [manager createDirectoryAtURL:resultsDir
          withIntermediateDirectories:NO
                           attributes:nil
                                error:nil];
    
        // Write the result message to a text file.
        NSURL* resultFile = [resultsDir URLByAppendingPathComponent:@"result.txt"];
        if ([manager fileExistsAtPath:[resultFile path]]) {
            // Append to the existing file
            NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:resultFile
                                                                     error:nil];
            [handle seekToEndOfFile];
            [handle writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
            [handle closeFile];
        } else {
            // Create and write to the file.
            [message writeToURL:resultFile
                     atomically:NO
                       encoding:NSUTF8StringEncoding error:nil];
        }
    }