2026年独占リモート Mac CI:Swift Testing(マクロ)と XCTest の混在をどう裁く?──コンパイル時間、並列度、Simulator クォータ、SSH ヘッドレス flaky の意思決定マトリクス+FAQ
独占リモート Mac の CI Worker では、Swift Testing(コンパイル時マクロ展開の負荷が大きい)とレガシーな XCTest が四半期単位で同居しがちです。狙いはフレームワークの宗教戦争ではなく、コンパイルの分割、並列度の上限、Simulator 起動の予算、SSH 越しの再現規律を一枚に落とすことです。以下は runbook に貼れる表と FAQ です。ツールチェーンの一貫性は Nix-darwin と専用 Mac mini で iOS CLI ツールチェーンを固定する記事、リモート Mac 上の SSH 自動化の感触は リモート物理 Mac mini の SSH 環境で開発を回す実践記事 と併読すると、セッション境界とスクリプトの置き場所が揃いやすいです。
1. まず効く痛み:コンパイル時間と「マクロ側/XCTest 側」の分割
Swift Testing は マクロ(例:#expect、@Suite など、ツールチェーンの表記に依存)に寄り、フロントエンドの仕事が増えて増分リビルドの表面積が広がります。XCTest と同一ターゲットに詰め込むと、小さな編集でもブリッジや生成コードの両方が揺れることがあります。
- 既定のおすすめ:Swift Testing 用の
*.xctest/SwiftPM テストターゲットを XCTest から物理的に分離し、メインスキームの Test Plan で PR とナイトリーのカバレッジを切り替える。 - CI ゲート:「UI のみ」PR で Swift Testing を黙って飛ばさないよう、パス規則や
CODEOWNERSで明示する。 - ツールチェーンの固定:
xcodebuild -versionと Swift 言語モードを runbook にログ化——マクロ挙動は XCTest 単体よりコンパイラ更新で動きやすいです。
2. コンパイル系トリアージ表
| 症状 | 最初の手 | コスト |
|---|---|---|
| クリーンビルドのテスト工程が長すぎる | Swift Testing ターゲットを分割し、モジュール安定化と DerivedData キャッシュキーを正規化する |
スキーム/Test Plan の運用が増える |
| 増分でもマクロファイルがホットスポット | 巨大共有フィクスチャの輸入経路を縮め、@testable import の扇を監査する |
コードの切り離しが必要 |
| ナイトリーはフル、PR は数分フィードバック | PR は Swift Testing のスモークのみ、マージキューまたは main で XCTest/統合をフル実行 | 「部分緑・全体赤」を拾う層が要る |
3. 並列度:混在=スレッドを二倍にできるわけではない
xcodebuild test の並列は Simulator プロセス、ディスク IO、コンパイラ子プロセスを掛け算します。Swift Testing と XCTest を同一呼び出しに詰めると、メモリ競合が「二回に分けて直列実行」より厳しくなることがあります。
- ベースライン:
-parallel-testing-enabled NOもしくは上限付き-maximum-parallel-testing-workersから始め、フレーク率を記録してから上げる。 - ジョブ分割:Swift Testing 用ジョブと XCTest 用ジョブに分け、同一独占 Mac 上でも
xcresultの帰属をきれいにする。 - UI テストの分離:UI とユニット/Swift Testing でピーク並列を共有しない——Simulator 起動嵐がコンパイル劣化の本丸を隠します。
4. Simulator クォータ:独占でも天井はある
他テナントとの競合が消えても、CoreSimulatorService の限界やメモリ圧は残ります。実効的な同時ブート上限は RAM、SSD 空き、watchOS/tvOS 併走の有無に強く相関します。
| メモリ層 | 同時 Simulator の出発点 | メモ |
|---|---|---|
| 16 GB | 重い UI/混在スイートは 1〜2。純ロジックは計測後にのみ上げる | Swift Testing と XCTest が重なるときは保守的に |
| 24〜32 GB | 宛先・スクリーンショット・録画次第で 2〜4 | memory_pressure と SSD レイテンシ尾を監視 |
| 64 GB 以上 | 上限は上がり得るが、Xcode/OS の不具合と IO ジッタで頭打ち | RAM 多い=並列無制限ではない |
ジョブごとに文書化する:端末を毎回捨てるか再利用するか、xcrun simctl shutdown all を叩くか、キーチェーンが GUI ログインに依存しないか(次節)。
5. SSH ヘッドレス flaky:テストを疑う前に環境を整える
SSH 越しの xcodebuild は、GUI セッションの形、キーチェーンの対話プロンプト、初回 Simulator 競合、ディスプレイ無し経路の GPU でフレークしがちです。Swift Testing と XCTest の論理差というより、並列を上げると顕在化します。
- セッション種別:
launchdエージェント、非対話ssh、コンソールログインユーザーを区別——コード署名とヘルパ権限が変わります。 - キーチェーン:CI での対話アンロック依存は断続的に落ちる。Runner 専用ユーザー、事前配線されたプロファイル、非対話シークレット注入とローテーション記録を runbook に。
- 再現のバー:「CI だけ赤」を同じ SSH コマンドでリプレイし、シードや
SIMCTL_CHILDを詰め、製品コードを書き換える前に N 連続成功を要求する。
6. 意思決定マトリクス(エグゼクティブ向け)
| 制約 | 分割の寄せ先 |
|---|---|
| PR レイテンシ敏感でマクロがコンパイル支配 | Swift Testing 専用ターゲット+ PR サブセット、フル XCTest/統合はナイトリーまたはマージで |
| 安定最優先でタイムアウトが散発 | 並列ワーカーを下げる、ジョブ分割、Simulator 起動の直列化 |
| GUI ログイン無しの SSH ヘッドレス | 並列を上げる前にセッション/キーチェーン/起動競合のチェックリストを潰す |
| レポートの単一の真実 | ジョブごとに xcresult パスを一つ、多段で上書きしない |
7. FAQ
Q1: 全部 Swift Testing に寄せて XCTest を消してよい?
方向性としては可。ただし CI 分割は段階的に:同居→モジュール単位移行→Test Plan のゲート明示。一括切替はコンパイルグラフの攪乱とフレーク帰属の混沌を同時に招きます。
Q2: マクロが遅い——-j や Runner を増やせば解決?
水平スケールは単一ターゲットのマクロ扇を隠しがちです。Swift フロントエンドがボトルネックなら並列ジョブは IO と Simulator 競合を増幅しやすい。まずターゲット分割とキャッシュキーです。
Q3: 独占 Mac なのにまだ flaky が残る——テストが悪い?
必ずしもそうではありません。SSH/キーチェーン/Simulator のチェックリストで二分し、ローカル GUI ユーザーでは緑・SSH だけ赤なら環境クラスのフレークを疑ってください。
この分割を「固定」するなら Mac mini が効く理由
Swift Testing と XCTest の同居には、予測可能なコンパイルグラフ、安定したユーザーセッション、混在 xcodebuild と Simulator に耐えるユニファイドメモリ帯域が要ります。Apple Silicon の Mac mini(M4 世代)は長時間ビルドと複数 Simulator 下でも効率が落ちにくく、独占セルフホスト Runner のベースライン計測に向きます。macOS は SSH 自動化、シェル、キーチェーン運用の経路が揃っており、不透明なマネージド Mac プールよりトリアージが素直です。Gatekeeper、SIP、FileVault は CI アカウントの露出面を抑えやすく、静音・小型・待機電力おおよそ 4 W 級のクラスは 24 時間パイプラインの TCO に効きます。
2026 年の並列度ベースラインと Test Plan を一台に集約したいなら、Mac mini M4 は依然としてコストパフォーマンスの良い入口です。プラン比較は SSHMac のトップページから進め、上のマトリクスを runbook に貼って運用に落としてください。