DevOps / CI·CD 2026年4月23日

2026-04-23 レンタル クラウド Mac CI:iOS テストプラン、並列 XCTest、xcresult 切り分け

MacXCode エンジニアリングチーム 2026年4月23日 約18分

iOS QA オーナーCI 保守者は、香港 / 日本 / 韓国 / シンガポール / 米国のレンタル Apple Silicon Mac で xcodebuild test を回すと、突発の -only-testing にはすぐ限界が来ます。本2026-04-23 ランはテストプランの標準化、宛先ごとの並列化、オブジェクト ストアへ安定名で xcresult を送る手順を示します。ヘッドレス Simulator テストDerivedData + xcresult の分離並列アーカイブの拡散の補完です。

リモート CI にテストプランが要る理由

*.xctestplan は版管理された意図です。デフォルトのテストターゲット、オプション、環境変数行列を列挙し、チームが Git でレビューできます。巨大なシェル文字列を CI の YAML に埋めるより上です。特に、ポイント リリースのあと「どの構成が本当に走ったのか」と PM に聞かれたときに効きます。プランを単一のスキームに結び、スキームは安定させます。Debug と Release、アドレス サニタイザ、不安定な UI スイートの一時無効化はプランでモデル化し、テストを消さないで済ませます。

テストプランとスキームのみ:判断表

方針 向く場面 SSH 上の運用性
コミット済み .xctestplan + -testPlan 名前 ノートとビルダーで再現。PR で差分 高—シャードあたり 1 コマンド
スキーム既定 + -only-testing スパイクとホットフィックス レーン 中—YAML の文字列が散らかる
別スキームにテストターゲットを分割 無関係なアプリが同居するモノレポ 低—スキームの二重管理

xcodebuild テスト起動の青写真

ホストで検証した Xcode に DEVELOPER_DIRをピン留めし、ジョブごとに Derived Data と明示的な結果バンドル パスでテストを走らせます。パスにジョブ ID を入れて、セルフホスト ランナーや社内スケジューラとの相関を簡単にします。

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}"

公表する数値: 既知のフレーク向けの既定 3 倍のローカル再試行と硬い上限。スイートあたり p95 が18 分を超えたらスケールの信号。12 コア級 M4 ホストでは、競合が壁時を支配する前に xcodebuild test2~4 同時までを予算化。

並列レーン、シャード、キュー

2 つの独立した軸があります。(a) 1 ホスト上の複数シミュレーターと、(b) 宛先 1 つずつの子ジョブ。(a) は費用には魅力的ですが、CoreSimulator とディスク I/O を非線形に鈍らせます。(b) はシンガポール米国東部の本格チームの扇状実行に近づきます。各シャードは CORESIMULATOR_HOST 接頭辞と Derived Data を専有し、独自の *.xcresultをアップロードします。並列 xcodebuild の記事のキュー規律を再利用し、テスト向けの再試行予算と、アーカイブ ジョブより 20~35% ゆるいシャードあたりタイムアウトを付けます。XCTest の起動のばらつきは本物です。

シャードの帰属、命名、再実行

子ジョブに Git 名とは独立した安定した CI_SHARD_IDを与えます。スラッシュや絵文字入りのブランチ名は素朴なシェル glob を壊します。オペが YAML を開かずログを読めるよう、indexcountを ID に埋めます。例:test-3-of-12はページャ スクリプトでは shard-uuidより分かりやすい。「失敗したテストだけ再実行」では、同じ DEVELOPER_DIRresultBundlePath 族を保ったまま、失敗したバンドル ID だけ -onlyTesting: リストに再マッピングします。こうすれば、ほぼ同じ名前の無関係な 2 つ目 xcresultがストレージ バケットで衝突しません。マージ条件が「全緑」なら、再実行ポリシーが新しいシャード ラベルを許すか曖昧にせず文書化します。曖昧さはフレークを方針インシーデントに変えます。

ユニットは数分で終わり、UIは昼を超える混成パイプラインでは、遅いシャードに速いフィードバックを阻ませないでください。部分的な xcresultステージング接頭辞に上げ、最後のシャードが通るまで「リリース」へ昇格させません。ダッシュボードは未完成のランから壁時の進行を出せても、本線の未完成と本線の緑を混ぜないようにします。DerivedData の記事の分離と相性が良く、同じ NVMe 上の兄弟シャードを触らず各シャードがクリーンアップでルートを消せます。

xcresult バンドル、マージ、保管するもの

xcresultは自己完結のテストレポートです。Xcode バージョン横断で保証されない方法で「ディスク上でマージ」しようとするより、シャードごとに 1 つを保ちます。下流では、品質ダッシュ向けに CI で JUnit や JSON へエクスポートしながら、インタラクティブ切り分け用に生 xcresultも保管するチームが多いです。保持は dSYM と同じ NVMe 方針に揃え、ビルドとテストを共有ホストで回す場合の表は dSYM とクラッシュ シンボリケーションを参照。

ディスク衛生: CoreSimulator は 1 週の混在シャードのあと数 GB の古い端末を漏らしがち—分離の掃除と同じ窓で掃引し、02:00 に「帳票上は十分だが危機的」にならないようにします。

ベアメタル上 XCTest のフレーク切り分け表

パターン 想定原因 最初の手
6 回に 1 回失敗、UI + アニメ触り タイムアウト対シム描画のばらつき アニメを安定化。タイムアウト引き上げ。成果物に画面録画
1 シャードでクラス全滅 シャード固有の環境、シード欠落 環境同値を主張。共有ボリュームを読専でマウント
月曜のあと全シャードが遅い OS 修正 + シミュレーター ランタイム変更 p95 を再ベース。Xcode/ランタイム版を明示的に固定

NVMe、1~2 TB オプション、「なぜ CI を無制限に?」

テスト レーンはアーカイブ専用より一時 I/Oを速く乗せます。レンタル Mac の1 TB か 2 TBで、週次スイープを計画:緑のブランチ向け 7 日越し xcresult 削除。既定ブランチは30 日。App Store Connect に使うタグに対応は90 日—コンプラが締めます。署名の怪しさとテストの怪しさが混ざるときは、キーチェーンとプロビジョニングの手順を再確認し、XCTest 出力の読み違いを防ぎます。

本ランを Simulator テスト基礎、アクセス パターン向け ヘルプ、テストとアーカイブ フリートを分ける ノード選定に接続。

FAQ:ヘッドレスでのテストプラン

質問 実践的な答え
テスト デバッグに VNC は? 自動化なら稀—成果物を使い、UI 向けのブレークグラスとして VNC
Mac あたりシャード数は? UI テストなら CPU コア / 3 から。1 週 p95 が安定してから上げる。
1 プランにユニット + UI 混在? 小アプリなら可。大規模リポはレイヤーでプラン分け、クリティカル パスを短く。

XCTest 重い CI には Mac mini M4 ベアメタル

MacXCode のMac mini M4は、CoreSimulator の性能と、騒がしい隣人のハイパーバイザ越しに置かれない NVMe を再現性高く扱います。XCTest p95 のメトリクスが本当に見る面です。香港 · 日本 · 韓国 · シンガポール · 米国のリージョンでテスト用ビルダーをアーカイブの隣に置き、同じSSHの流儀、成果物多めなら 1~2 TB。再試行予算が I/O か CPU か、テストプランの誤設定でない限り、料金から弾力よくノードを足せます。

テスト品質向けクラウド Mac 容量

M4 · NVMe · 多リージョン