Pierwsze kroki z testami pętli gry na iOS

Dzięki testom pętli gry możesz tworzyć testy natywne dla silnika gry, a następnie uruchamiać je w Laboratorium testów na wybranych urządzeniach. Dzięki temu nie trzeba pisać dla różnych interfejsów ani platform testowania. Test pętli gry symuluje działania prawdziwego gracza, a po uruchomieniu w Laboratorium pozwala na szybkie i skalowalne sprawdzenie, czy gra działa dobrze dla użytkowników.

Z tej strony dowiesz się, jak przeprowadzić test pętli gry, a następnie wyświetlić wyniki testu i zarządzać nimi na stronie Laboratorium w konsoli Firebase. Możesz też jeszcze bardziej dostosować testy za pomocą funkcji opcjonalnych, takich jak zapisywanie wyników testu niestandardowego lub wcześniejsze zakończenie testu.

Co to jest test pętli gry?

Zapętlenie to całkowite lub częściowe przejście testu w grze. Test możesz przeprowadzić lokalnie na symulatorze lub na grupie urządzeń w Laboratorium. Testy pętli gry mogą być wykorzystywane do:

  • Rozegraj grę tak, jak grałby w nią użytkownik. Możesz utworzyć skrypt powodujący dane wejściowe użytkownika, pozwolić mu na bezczynność lub zastąpić użytkownika sztuczną inteligencją (jeśli np. masz wdrożoną AI w grze wyścigowej, możesz wyznaczyć kierowcę AI pod kontrolą kierowcy).

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

  • Przeprowadź test techniczny, np. skompiluj i uruchom wiele programów do cieniowania, i sprawdź, czy wyniki są zgodne z oczekiwaniami.

Krok 1. Zarejestruj schemat niestandardowego adresu URL Laboratorium

Najpierw musisz zarejestrować schemat niestandardowego adresu URL w Laboratorium Firebase w swojej aplikacji:

  1. W Xcode wybierz miejsce docelowe projektu.

  2. Kliknij kartę Informacje i dodaj nowy typ adresu URL.

  3. W polu Schematy adresów URL wpisz firebase-game-loop. Możesz też zarejestrować schemat niestandardowego adresu URL, dodając go do pliku konfiguracyjnego Info.plist projektu w dowolnym miejscu 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 przeprowadzania testów w Laboratorium.

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

Jeśli Twoja aplikacja ma zarejestrowanych wiele schematów niestandardowych adresów URL i chcesz uruchomić w teście wiele pętli (tzw. scenariuszy), musisz określić, które pętle mają być uruchamiane w aplikacji.

W delegacji do 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 wykonujesz kilka pętli, bieżąca pętla jest przekazywana jako parametr do adresu URL używanego do uruchomienia aplikacji. Numer bieżącej pętli możesz też uzyskać, analizując obiekt URLComponents użyty do pobrania schematu niestandardowego 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 schematu niestandardowego adresu URL w Laboratorium możesz uruchomić test w konsoli Firebase lub za pomocą gcloud beta CLI. Wygeneruj plik IPA swojej aplikacji (musisz go później znaleźć).

Przeprowadzanie testu w konsoli Firebase

  1. Otwórz konsolę Firebase i utwórz projekt, jeśli jeszcze jej nie masz.

  2. Na stronie Laboratorium w konsoli Firebase kliknij Przeprowadź pierwszy test > Uruchom pętlę gry na iOS.

  3. W sekcji Przesyłanie aplikacji kliknij Przeglądaj i wybierz plik IPA aplikacji (jeśli jeszcze nie został wygenerowany, wygeneruj plik IPA dla swojej aplikacji).

  4. Opcjonalnie: jeśli chcesz uruchomić kilka pętli (tzw. scenariuszy) jednocześnie lub wybrać konkretne pętle, wpisz ich liczby w polu Scenariusze.

    Jeśli na przykład wpiszesz wartości „1–3, 5”, Laboratorium uruchomi pętle 1, 2, 3 i 5. Domyślnie (jeśli nie wprowadzisz niczego w polu Scenariusze), Laboratorium uruchamia tylko pętlę 1.

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

Przeprowadzanie testu za pomocą gcloud beta CLI

  1. Skonfiguruj lokalne środowisko pakietu SDK gcloud, a potem zainstaluj komponent gcloud beta.

  2. Uruchom polecenie gcloud beta firebase test ios run i użyj tych flag, aby skonfigurować uruchomienie:

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

Wymagane: ścieżka bezwzględna (Google Cloud Storage lub system plików) do pliku IPA aplikacji. Ta flaga jest ważna tylko podczas wykonywania testów pętli gry.

--scenario-numbers

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

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

--device-model

Fizyczne urządzenie, na którym chcesz przeprowadzić test (sprawdź, których dostępnych urządzeń możesz użyć).

--timeout

Maksymalny czas trwania testu. Możesz wpisać liczbę całkowitą określającą czas trwania w sekundach lub liczbę całkowitą i wyliczenie, aby przedstawić czas jako dłuższy okres.

Przykład:

  • --timeout=200 wymusza zakończenie testu, gdy potrwa do 200 sekund.
  • --timeout=1h wymusza zakończenie testu po upływie maksymalnie godziny.

Na przykład to polecenie uruchamia 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 gcloud CLI znajdziesz w dokumentacji referencyjnej.

Uruchamianie testu lokalnie

Aby przeprowadzić test lokalnie, wczytaj grę mobilną w symulatorze i uruchom:

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
  • Identyfikator UDID symulatora możesz znaleźć, uruchamiając polecenie instruments -s devices.

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

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

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 kończenie testu

Domyślnie test pętli gry trwa do momentu upłynięcia 5-minutowego limitu czasu, nawet jeśli wszystkie pętle zostały wykonane. Po upływie 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 schemat niestandardowego adresu URL firebase-game-loop-complete w narzędziu AppDelegate Twojej aplikacji. 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 uruchamia następną. Gdy nie ma więcej pętli do uruchomienia, test się kończy.

Zapisz wyniki testu niestandardowego

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

  • Przesyłane są wszystkie pliki wyników wyszukiwania niezależnie od ich typu, rozmiaru i liczby.

  • Test Lab nie przetwarza wyników, dopóki wszystkie pętle w teście nie zostaną zakończone. Jeśli test obejmuje wiele pętli zapisujących dane wyjściowe, należy dołączyć je do unikalnego pliku wyników lub utworzyć plik wyników dla każdej pętli. W ten sposób unikniesz zastąpienia wyników z poprzedniej pętli.

Aby skonfigurować test i zapisać wyniki testu niestandardowego:

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

  2. W dowolnym miejscu w kodzie aplikacji (np. w imieniu jej przedstawiciela) dodaj:

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