Konsistenzprüfung für Xcode-Testpläne auf Cloud-Macs

Konsistenzprüfung für Xcode-Testpläne auf Cloud-Macs

Nachdem ein Team Unit-, API- und UI-Tests auf mehrere Xcode-Testpläne verteilt hat, sind fehlgeschlagene Tests meist nicht das häufigste Problem. Häufiger werden Tests überhaupt nicht wie erwartet ausgeführt: Jemand ändert lokal im Scheme den Standardplan, überspringt vorübergehend einen Testfall und committet anschließend die Datei, oder passt Umgebungsvariablen an, ohne die Pipeline entsprechend zu aktualisieren. Ein Cloud-Mac führt die im Repository hinterlegte Konfiguration exakt aus. Deshalb sollte der erste Schritt nicht darin bestehen, weitere Wiederholungsversuche einzubauen, sondern den Testplan selbst wie prüfpflichtigen Code zu behandeln.

Einen einzigen nachvollziehbaren Einstiegspunkt festlegen

Das Scheme muss als gemeinsam genutzte Datei vorliegen, üblicherweise unter App.xcodeproj/xcshareddata/xcschemes/App-CI.xcscheme. Verlassen Sie sich nicht auf xcuserdata im Benutzerverzeichnis, da die dort gespeicherte Konfiguration nicht zuverlässig in die Versionsverwaltung gelangt.

Verweisen Sie in der Test Action des Schemes auf die im Repository enthaltene Datei App-CI.xctestplan und lassen Sie die Pipeline den Namen des Plans explizit übergeben. Sobald ein Build-Knoten seine Arbeit aufnimmt, sollte er zunächst prüfen, ob der Plan verfügbar ist:

set -euo pipefail

xcodebuild \
  -workspace App.xcworkspace \
  -scheme App-CI \
  -showTestPlans

xcodebuild \
  -workspace App.xcworkspace \
  -scheme App-CI \
  -testPlan App-CI \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  test

-testPlan darf nicht weggelassen werden. Andernfalls kann der Befehl nach einer Änderung des Scheme-Standardwerts weiterhin erfolgreich ausgeführt werden, obwohl inzwischen eine andere Testmenge läuft.

Die Plandatei als überprüfbaren Vertrag definieren

Eine .xctestplan-Datei liegt im JSON-Format vor und eignet sich daher für statische Prüfungen. Die Qualitätskontrolle sollte mindestens vier Feldgruppen abdecken:

Prüfpunkt Erforderliche Regel Bedeutung bei einem Fehler
configurations Muss eine CI-Konfiguration enthalten Der Pipeline-Einstieg wurde gelöscht oder umbenannt
testTargets Muss die vereinbarten Targets enthalten Eine Testgruppe wurde nicht ausgeführt
skippedTests Darf nur Einträge aus der Positivliste enthalten Es wurden nicht begründete Überspringungen hinzugefügt
environmentVariableEntries Vertrauliche Werte sind verboten, erforderliche Schlüssel müssen vorhanden sein Die Umgebung ist abgewichen oder Informationen sind in das Repository gelangt

Vergleichen Sie nicht einfach die Textreihenfolge der gesamten JSON-Datei. Xcode kann Arrays neu anordnen oder Felder ergänzen; ein wortwörtlicher Vergleich würde dadurch bedeutungslose Fehler erzeugen. Stattdessen sollte die Struktur eingelesen und nur auf die Regeln geprüft werden, von denen das Team tatsächlich abhängt.

Die Prüfung eines Testplans soll nicht jede Änderung verhindern. Sie soll vor dem Zusammenführen sichtbar machen, welche Tests nicht mehr ausgeführt werden und welche Umgebungsbedingungen geändert wurden.

Fehlende Targets und übersprungene Tests per Skript abfangen

Das folgende Skript prüft die CI-Konfiguration, die erforderlichen Test-Targets und nicht registrierte übersprungene Tests. Die Positivliste sollte sehr kurz bleiben, und im Code-Review muss für jeden Eintrag erläutert werden, unter welcher Bedingung er wieder entfernt wird.

#!/usr/bin/env python3
import json
import sys
from pathlib import Path

plan = json.loads(Path("App-CI.xctestplan").read_text())
required_targets = {"AppTests", "AppIntegrationTests"}
allowed_skips = {
    "AppIntegrationTests/testTemporaryServerResponse"
}

config_names = {item["name"] for item in plan.get("configurations", [])}
if "CI" not in config_names:
    sys.exit("Missing CI test configuration")

targets = plan.get("testTargets", [])
target_names = {
    item.get("target", {}).get("name")
    for item in targets
}
missing = required_targets - target_names
if missing:
    sys.exit(f"Missing test targets: {sorted(missing)}")

actual_skips = {
    test
    for item in targets
    for test in item.get("skippedTests", [])
}
unexpected = actual_skips - allowed_skips
if unexpected:
    sys.exit(f"Unapproved skipped tests: {sorted(unexpected)}")

Führen Sie das Skript vor dem Testbefehl aus. Bei einem Fehler darf es die Plandatei nicht automatisch umschreiben, denn eine automatische Korrektur könnte eine absichtliche Konfigurationsänderung durch einen Entwickler verschleiern.

Ablaufbedingungen für die Positivliste festlegen

Die Positivliste darf nicht zu einer dauerhaften Ablage für Ausnahmen werden. Jeder Eintrag benötigt mindestens einen zugehörigen Fehlerbericht, eine verantwortliche Person und eine Bedingung für seine Entfernung. Wenn das Team keine zweite strukturierte Datei pflegen möchte, kann es diese Angaben im Code-Review-Template verpflichtend machen und regelmäßig per Skript die aktuelle Liste ausgeben lassen.

Stabile Variablen und Pipeline-Secrets trennen

Testpläne eignen sich für Schalter, die sich nicht von Knoten zu Knoten ändern, etwa UITEST_MODE=1, eine feste Sprache oder einen Modus für simulierte Dienste. Zugriffstoken, private Schlüssel und kurzlebige Anmeldedaten gehören weder in die Plandatei noch als Klartextparameter in das Scheme.

Die Pipeline auf einem Cloud-Mac kann Secrets vor der Ausführung injizieren und sie dem Testprozess über Umgebungsvariablen bereitstellen. Das Prüfsystem kontrolliert dann lediglich, ob die erforderlichen Schlüssel vorhanden sind und ob ihre Werte aus einer zulässigen festen Menge stammen. So bleibt der Plan reproduzierbar, ohne vertrauliche Informationen in das Repository einzubringen.

Achten Sie außerdem auf das Target, in dessen Kontext Variablen aufgelöst werden. Wenn ein Plan auf ein inzwischen umbenanntes Target verweist, lässt sich die Datei möglicherweise weiterhin in der Xcode-Oberfläche öffnen, während die Variablen zur Laufzeit nicht mehr wie erwartet aufgelöst werden. Bei einer Umbenennung im Projekt sollte die Planprüfung deshalb zusammen mit xcodebuild -list ausgeführt werden.

Ausreichende Belege für Fehler aufbewahren

Führen Sie die vollständigen Tests erst nach bestandener Prüfung aus und schreiben Sie das Ergebnis-Bundle in ein festes Verzeichnis:

rm -rf artifacts/App-CI.xcresult

xcodebuild \
  -workspace App.xcworkspace \
  -scheme App-CI \
  -testPlan App-CI \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  -resultBundlePath artifacts/App-CI.xcresult \
  test

Bewahren Sie bei einem Fehler drei Informationen auf: die aktuelle .xctestplan-Datei, den tatsächlich ausgeführten Befehl und das .xcresult-Bundle. Nur das Ende der Konsolenausgabe zu speichern reicht nicht aus, um festzustellen, ob die Testlogik fehlgeschlagen ist, ein Target nicht geladen wurde oder sich die Plankonfiguration geändert hat.

Auch bei der Ausführung auf fest zugewiesenen Testknoten bei ZoneMini sollte die statische Prüfung vor jedem Auftrag erneut erfolgen. Gehen Sie nicht davon aus, dass eine langfristig laufende Umgebung automatisch unverändert bleibt. Das Shared Scheme definiert den Einstiegspunkt, der Testplan beschreibt die Testmenge, das Prüfsystem begrenzt Änderungen und das Ergebnis-Bundle bewahrt die Nachweise auf. Erst wenn alle vier Ebenen vorhanden sind, hat die Aussage „Tests bestanden“ eine stabile Bedeutung.

Häufig gestellte Fragen

Warum reicht ein festes xcodebuild-Kommando im CI nicht aus?

Das Kommando fixiert nur Scheme und Planname. Ziele, Ausnahmen und Variablen innerhalb der .xctestplan-Datei können sich weiterhin ändern und benötigen deshalb eine eigene Prüfung.

Sollten skippedTests grundsätzlich verboten werden?

Nein. Eine begründete temporäre Ausnahme darf in einer Freigabeliste mit Verantwortlichem und Entfernungskriterium stehen. Neue, nicht registrierte Ausnahmen sollten den Merge blockieren.

Wie verwenden lokaler Mac und Cloud-Mac garantiert denselben Testplan?

Das Scheme gehört nach xcshareddata/xcschemes, der Plan ins Repository und der CI-Aufruf erhält ein festes -testPlan. Mit -showTestPlans wird seine Sichtbarkeit vorab geprüft.

DEDIZIERTER BUILD-SLOT

Wählen Sie einen exklusiven Cloud-Mac für kontinuierliche Build-Aufgaben

Prüfen Sie M4, Arbeitsspeicher, Speicherplatz, Standort und Abrechnungszeitraum und binden Sie die feste Build-Umgebung anschließend in Ihre bestehende Pipeline ein.

Konfiguration auswählen und bestellen