DevOps / CI·CD 23 avril 2026

2026-04-23 Plans de tests iOS, XCTest parallèle et tri xcresult pour la CI sur Mac cloud loué

Équipe technique MacXCode 23 avril 2026 ~18 min de lecture

Les responsables QA iOS et les mainteneurs CI qui exécutent xcodebuild test sur des Mac Apple Silicon loués à HK / JP / KR / SG / US dépassent vite les drapeaux ad hoc -only-testing. Ce runbook du 2026-04-23 normalise les plans de test, montre comment paralléliser par destination et comment livrer des paquets xcresult vers votre stockage objet avec des noms stables—en complément des tests simulateur headless, de DerivedData et isolation xcresult et des jobs xcodebuild parallèles pour les archives.

Pourquoi les plans de test ont leur place en CI distante

Un *.xctestplan est une intention versionnée : il liste les cibles de test par défaut, les options et les matrices de variables d'environnement que votre équipe peut relire dans Git. Cela bat de longues chaînes shell embarquées dans un YAML CI—surtout quand un PM demande « quelles configurations ont réellement tourné » après une version ponctuelle. Couplez les plans à un schéma unique et gardez le schéma stable ; le plan est l'endroit où vous modélisez Debug contre Release, les bascules du sanitizer d'adresses ou la désactivation temporaire de suites UI instables sans supprimer les tests.

Plan de test contre schéma seul : tableau de décision

Approche Quand elle brille Exploitabilité en SSH
.xctestplan validé + -testPlan Name Reproductibilité postes et builders ; diffs en PR Élevée—une commande par fragment
Valeurs par défaut du schéma + -only-testing Pics et voies correctifs Moyenne—explosion de chaînes dans le YAML
Découpage des cibles de test sur plusieurs schémas Monorepos avec apps sans lien Plus faible—maintenance de schémas dupliquée

Plan d'invocation xcodebuild test

Épinglez DEVELOPER_DIR sur le Xcode validé sur l'hôte, puis lancez les tests avec chemin de paquet de résultats explicite et derived data par job. Gardez les identifiants de job dans le chemin pour simplifier la corrélation avec les runners auto-hébergés ou vos orchestrateurs maison.

DEVELOPER_DIR=/Applications/Xcode.app xcodebuild test -workspace App.xcworkspace -scheme App -testPlan Nightly -destination 'platform=iOS Simulator,name=iPhone 16' -resultBundlePath "$CI_RESULTS/run-${CI_SHARD_ID}.xcresult" -derivedDataPath "$CI_DERIVED_DATA/${CI_SHARD_ID}"

Chiffres à publier : fixez par défaut de réessai local pour les flakiness connues avec un plafond dur, suivez le p95 par suite au-dessus de 18 minutes comme signal d'échelle, et budgétez 2 à 4 processus xcodebuild test concurrents sur un hôte classe M4 12 cœurs avant que la contention ne domine le temps mural.

Voies parallèles, fragments et files

Il existe deux axes distincts : (a) plusieurs simulateurs sur un hôte contre (b) jobs enfants séparés chacun avec une destination. L'option (a) est séduisante pour le coût mais pousse CoreSimulator et les E/S disque vers des ralentissements non linéaires. L'option (b) reflète comment les équipes sérieuses à Singapour et US Est ventilent : chaque fragment possède son préfixe CORESIMULATOR_HOST et son derived data, puis téléverse son propre *.xcresult. Réutilisez la discipline de file de l'article xcodebuild parallèle, mais avec des budgets de réessai propres aux tests et des timeouts par fragment 20 à 35 % plus souples que vos jobs d'archive—la variance de démarrage XCTest est réelle.

Propriété des fragments, nommage et relances

Donnez à chaque job enfant un CI_SHARD_ID stable indépendant du nom de branche Git, car les branches avec barres obliques et émojis cassent le globbing shell naïf. Encodez index et total dans cet ID pour que les opérateurs lisent les journaux sans ouvrir le YAML : par ex. test-3-of-12 bat shard-uuid dans les scripts de pager. Quand quelqu'un clique « relancer uniquement les tests en échec », apprenez à votre orchestration à ne remapper que les identifiants de bundle échoués vers des listes -only-testing: tout en conservant la même famille DEVELOPER_DIR et resultBundlePath—cela évite un second xcresult sans rapport avec presque le même nom qui entre en collision dans votre compartiment. Si vous conditionnez les fusions sur « tout vert », documentez si les politiques de relance peuvent substituer une nouvelle étiquette de fragment ; l'ambiguïté ici transforme une flakiness en incident de politique.

Pour des pipelines mixtes où les tests unitaires finissent en minutes et les tests UI dépassent le déjeuner, ne laissez pas les fragments lents bloquer un retour rapide : publiez des téléversements partiels xcresult vers un préfixe de staging, puis promouvez l'ensemble vers « release » seulement quand le dernier fragment passe—votre tableau de bord peut toujours montrer la progression au mur de l'horloge depuis des paquets partiels sans confondre des exécutions incomplètes avec une ligne principale verte. Ce motif s'accouple naturellement aux pratiques d'isolation de l'article DerivedData, car chaque fragment peut supprimer sa racine DerivedData indépendamment pendant le nettoyage tout en laissant les fragments voisins intacts sur la même NVMe.

Paquets xcresult, fusion et quoi stocker

Chaque xcresult est un rapport de test autonome—gardez-en un par fragment plutôt que de « fusionner sur disque » de façons qu'Xcode ne garantit pas entre versions. En aval, beaucoup d'équipes exportent JUnit ou JSON en CI pour alimenter des tableaux de qualité, tout en archivant le xcresult brut pour le tri interactif. Alignez la rétention sur la même politique NVMe que pour les dSYM : voyez dSYM et symbolisation des crashs pour des matrices de rétention lorsque tests et builds partagent un hôte.

Hygiène disque : CoreSimulator peut laisser fuiter des Go d'appareils obsolètes après une semaine de fragments mélangés—balayez dans la même fenêtre que votre nettoyeur d'isolation pour que l'espace libre ne soit jamais « bon sur le papier mais critique à 02:00 ».

Matrice de tri des flakiness XCTest sur bare metal

Motif Cause racine probable Première action
1 échec sur 6, tests touchent UI + animations Timeout contre variance de rendu simulateur Stabiliser les animations ; augmenter le timeout + capturer des enregistrements d'écran dans les artefacts
Toute la classe échoue dans un fragment Environnement spécifique au fragment, graine de données manquante vérifier la parité d'environnement ; monter les fixtures en lecture seule depuis un volume partagé
Tous les fragments ralentissent après un lundi Patch OS + changement de runtime simulateur Re-baseliner le p95, épingler explicitement les versions Xcode/runtime

NVMe, options 1–2 To et « pourquoi pas une CI illimitée ? »

Les voies de test multiplient les E/S transitoires plus vite que les voies d'archive seules. Avec des configurations 1 To ou 2 To sur un Mac loué, planifiez des balayages hebdomadaires : supprimez les xcresult verts de plus de 7 jours, conservez 30 jours pour les branches par défaut et 90 jours pour les tags utilisés dans App Store Connect—votre équipe conformité peut resserrer cela. Quand la flakiness de signature se mêle à la flakiness de test, revérifiez le guide trousseau et provisionnement pour ne pas mal lire la sortie XCTest.

Reliez ce runbook aux bases des tests simulateur, à l'aide pour les modes d'accès et aux tarifs lorsque vous séparez les flottes de test et d'archive.

FAQ : plans de test en environnements sans tête

Question Réponse pratique
Ai-je besoin de VNC pour déboguer les tests ? Rarement pour l'automatisation—utilisez les artefacts et VNC en dernier recours pour les problèmes UI.
Combien de fragments par Mac ? Commencez avec cœurs CPU / 3 pour les tests UI ; n'augmentez qu'après une semaine de p95 stable.
Dois-je mélanger unitaires + UI dans un même plan ? OK pour les petites apps ; pour les gros dépôts, scindez les plans par couche pour raccourcir le chemin critique vers le signal.

Pourquoi le Mac mini M4 bare metal convient à une CI XCTest lourde

Les nœuds Mac mini M4 sur MacXCode offrent des performances déterministes de CoreSimulator et une NVMe qui ne passe pas par un hyperviseur bruyant—exactement la surface dont se soucient les métriques p95 XCTest. Avec des régions sur HK · JP · KR · SG · US, vous pouvez colocaliser les builders de test près des hôtes d'archive tout en gardant les mêmes flux SSH, ajouter 1–2 To pour les organisations riches en artefacts et ajouter élastiquement des hôtes depuis les tarifs lorsque vos budgets de réessai prouvent que vous êtes lié par l'I/O ou le CPU—et non par des plans de test mal configurés.

Ajouter de la capacité Mac cloud pour la qualité des tests

M4 · NVMe · Multi-région