Wenn derselbe Commit auf dem Rechner eines Entwicklers alle Tests durchläuft, auf einem Cloud-Mac jedoch nur einen Teil davon ausführt, liegt die häufigste Ursache nicht im Testcode. Meist ist die .xctestplan-Datei unbemerkt abgewichen: Jemand hat in Xcode vorübergehend Testfälle übersprungen, Diagnoseoptionen deaktiviert oder Umgebungsvariablen gespeichert, die nur auf dem eigenen Rechner funktionieren. Behandeln Sie XCTestPlan deshalb als Build-Eingabe und nicht als ergänzende Einstellung der grafischen Oberfläche.
Zuerst die Grenzen des Testvertrags festlegen
Ein reproduzierbarer Testeinstieg umfasst mindestens ein freigegebenes Scheme, einen XCTestPlan, ein Ausführungsziel und die Befehlszeilenargumente. Prüfen Sie zunächst, ob Scheme und Testplan tatsächlich über die Befehlszeile gefunden werden:
WORKSPACE="${WORKSPACE:-App.xcworkspace}"
SCHEME="${SCHEME:-App}"
xcodebuild \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-showTestPlans
Wenn der erwartete Plan nicht in der Ausgabe erscheint, prüfen Sie zuerst, ob das Scheme als Shared markiert ist, die Plandatei zum Repository gehört und die Test-Aktion des Schemes auf diesen Plan verweist. Ergänzen Sie keinen fehlenden Plan provisorisch über CI-Parameter. Andernfalls driften der lokale Einstieg und die Pipeline weiter auseinander.
Folgende Punkte des Plans sollten ausdrücklich geprüft werden:
| Element | Zu bestätigender Sachverhalt | Typische Drift |
|---|---|---|
| Test Targets | Welche Unit- und UI-Tests ausgeführt werden | Neues Target wurde nicht hinzugefügt |
| Selected Tests | Ob nur ausgewählte Testfälle ausgeführt werden | Debug-Auswahl wurde eingecheckt |
| Skipped Tests | Ob jeder übersprungene Test einen Verantwortlichen und eine Frist hat | Fehlgeschlagener Test bleibt dauerhaft verborgen |
| Configurations | Sprache, Region und Startargumente | Lokale Konfiguration überschreibt die Standardkonfiguration |
| Diagnostics | Strategie für Absturz-, Thread- und Leistungsdiagnosen | Zur Beschleunigung versehentlich deaktiviert |
| Parallelization | Welche Targets parallel ausgeführt werden dürfen | Tests mit gemeinsamem Zustand stören sich gegenseitig |
Einen Test zu überspringen ist keine Fehlerbehebung. Jeder neu hinzugefügte übersprungene Test sollte wie eine Codeänderung geprüft werden und klare Bedingungen für seine Reaktivierung enthalten.
Lesbare, normalisierte Diffs erzeugen
XCTestPlan ist ein strukturiertes Dateiformat. Bei der direkten Prüfung des Rohtexts lenken die Reihenfolge der Felder und automatisch erzeugte Kennungen leicht von den relevanten Änderungen ab. Speichern Sie deshalb eine normalisierte Baseline im Repository, aus der nur Konfigurationskennungen entfernt werden, die keine Auswirkungen auf die Ausführungssemantik haben:
PLAN="App.xctestplan"
CURRENT=".ci/xctestplan.current.json"
BASELINE=".ci/xctestplan.baseline.json"
mkdir -p .ci
plutil -convert json -o - "$PLAN" |
jq -S 'del(.configurations[]?.id)' > "$CURRENT"
diff -u "$BASELINE" "$CURRENT"
Prüfen Sie bei der erstmaligen Einrichtung $CURRENT manuell, kopieren Sie die Datei anschließend als Baseline und committen Sie sie. Bei späteren Pipeline-Läufen wird nur noch die aktuelle Datei erzeugt und mit diff verglichen. Targets, übersprungene Tests, Umgebungsvariablen, Argumente und Diagnoseoptionen müssen vollständig erhalten bleiben. Entfernen Sie keine fachlich relevanten Felder, nur um einen „sauberen Diff“ zu erhalten.
Auch das Normalisierungsskript gehört zur Testinfrastruktur. Änderungen am Skript und am Plan sollten im selben Merge Request sichtbar sein. Andernfalls kann bereits eine einzige gelockerte Filterregel dazu führen, dass jede spätere Drift unsichtbar bleibt.
Sensible Werte und Host-Abhängigkeiten abfangen
Plandateien eignen sich zum Speichern von Variablennamen, nicht jedoch für Token, Passwörter, private Schlüssel oder Entwicklerverzeichnisse. Extrahieren Sie zunächst rekursiv alle aktivierten Umgebungsvariablen:
plutil -convert json -o - App.xctestplan |
jq -r '
.. |
objects |
.environmentVariableEntries? // empty |
.[]? |
select(.enabled == true) |
[.key, .value] |
@tsv
'
Achten Sie bei der Prüfung der Ausgabe besonders auf drei Arten von Einträgen: lange Zeichenfolgen, die wie Schlüssel aussehen, absolute Pfade nach dem Muster /Users/Name/ sowie Pfade zu Werkzeugen, die nur in einer interaktiven Shell verfügbar sind. Tatsächliche Geheimnisse sollten zur Laufzeit aus der kontrollierten CI-Umgebung injiziert werden. Der Testcode liest lediglich die Variablennamen und gibt eine eindeutige Fehlermeldung aus, wenn ein Wert fehlt.
Unkontrollierte Überschreibungsprioritäten vermeiden
XCTestPlan, Scheme, xcodebuild-Argumente und Testcode können jeweils Startargumente festlegen. Definieren Sie daher eine eindeutige Priorität: Der Plan enthält stabile Standardwerte, die CI injiziert ausschließlich sensible Werte und Kennungen des aktuellen Laufs, und der Testcode verändert keine prozessweiten Einstellungen. Wenn die Pipeline -only-testing oder -skip-testing verwendet, müssen diese Argumente in einem prüfbaren Skript stehen. Sie dürfen nicht in einem temporären Eingabefeld der Job-Oberfläche verborgen sein.
Mit einem festen Ziel ausführen und Nachweise sichern
Wählen Sie zunächst mit xcrun simctl list devices available ein Gerät aus, das auf dem aktuellen Knoten installiert ist, und übergeben Sie dessen UDID als Pipeline-Eingabe. Ein festgelegtes Gerät mit definierter Runtime macht Abweichungen leichter nachvollziehbar als eine vage Auswahl des „neuesten Systems“.
DEVICE_UDID="${DEVICE_UDID:?Set DEVICE_UDID from simctl}"
RESULT_PATH="${RESULT_PATH:-artifacts/CI.xcresult}"
rm -rf "$RESULT_PATH"
mkdir -p "$(dirname "$RESULT_PATH")"
xcodebuild test \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-testPlan CI \
-destination "platform=iOS Simulator,id=$DEVICE_UDID" \
-resultBundlePath "$RESULT_PATH"
Speichern Sie unabhängig von Erfolg oder Fehlschlag die .xcresult-Datei, den vollständigen Befehl, die Commit-Kennung, die Xcode-Version und die UDID des ausgewählten Geräts. Bewahren Sie nicht nur die letzten Dutzend Protokollzeilen auf. Nicht ausgeführte Tests, Prozessabstürze und fehlgeschlagene Assertions erfordern unterschiedliche Nachweise. Das Ergebnis-Bundle erhält die Testhierarchie, Anhänge und Diagnoseinformationen.
Beginnen Sie bei der parallelen Ausführung mit konservativen Werten. Test-Targets, die dieselbe Datenbank, einen festen Port oder gemeinsame Dateien verwenden, sollten nicht sofort parallel ausgeführt werden. Isolieren Sie zunächst den Zustand vollständig und aktivieren Sie die Parallelisierung anschließend schrittweise, statt Race Conditions durch Wiederholungsversuche zu kaschieren.
Die Prüfung als Merge-Gate etablieren
Das abschließende Gate sollte immer in derselben Reihenfolge ausgeführt werden: Prüfen, ob das Scheme den Plan findet, die normalisierte Datei erzeugen, sie mit der Baseline vergleichen, nach sensiblen Werten und absoluten Pfaden suchen, die Liste übersprungener Tests kontrollieren und erst danach die Tests starten. So schlagen Konfigurationsfehler bereits vor dem Start des Simulators fehl, was Warte- und Diagnosezeit spart.
Verwenden Sie vor dem Commit folgende Checkliste:
- Das Scheme ist freigegeben und die Plandatei wird von der Versionsverwaltung erfasst.
- Neue Test-Targets wurden dem richtigen Plan hinzugefügt.
- Für alle übersprungenen Tests sind Grund, Verantwortlicher und Bedingungen für die Reaktivierung dokumentiert.
- Der Plan enthält weder echte sensible Werte noch persönliche Verzeichnisse.
- Die CI enthält keine verborgenen Parameter, die den Testumfang überschreiben.
- Geräte-UDID, Xcode-Version und Ergebnis-Bundle werden aufgezeichnet.
- Die Normalisierungsregeln entfernen keine Felder mit Ausführungssemantik.
- Auch bei fehlgeschlagenen Läufen wird
.xcresultarchiviert.
Wenn jede Änderung am XCTestPlan im Code-Review verständlich nachvollzogen werden kann, ist „lokal alles grün, in der Cloud fehlen Tests“ kein sporadisches Rätsel mehr. Stattdessen wird daraus eine Konfigurationsabweichung, die sich bereits vor der Ausführung blockieren lässt.
Häufig gestellte Fragen
Warum genügt ein gemeinsam genutztes Xcode-Scheme nicht?
Das Scheme legt den Einstieg fest, doch XCTestPlan kann Ziele, Konfigurationen, Argumente, Variablen, Sprachen und ausgeschlossene Tests ändern. Die CI muss alle Ebenen festschreiben.
Dürfen Zugriffstoken in XCTestPlan gespeichert werden?
Nein. Im Plan stehen nur Variablennamen oder unkritische Standardwerte. Geheimnisse werden zur Laufzeit aus der kontrollierten CI-Umgebung injiziert und nicht protokolliert.
Kann die Normalisierung wichtige Änderungen verbergen?
Bei einem zu breiten Filter ja. Entfernen Sie nur generierte Kennungen ohne Ausführungsbedeutung und behalten Sie Ziele, Auswahl, Ausschlüsse, Optionen und Konfigurationsnamen bei.
Einen dedizierten Cloud-Mac für Ihre Entwicklungs-Pipeline konfigurieren
MangoVM bietet dedizierte physische Knoten mit Apple Silicon in den Varianten M4 und M4 Pro. Wählen Sie Laufzeit, Region und zusätzliche Speicheroptionen, um die vollständigen Bestelldetails zu prüfen.