當單一 Mac 以序列方式跑完所有 UI 測試時,行動版發佈節奏往往卡住。本篇說明何時值得分片、如何在同一決策矩陣中比較單機與多機策略、如何定義 Runner 標籤與執行時間預算,並以八個具體步驟將 XCTest UI 工作分散到專用的 Mac mini M4 雲端主機上,讓佇列數學可預測。
若您正在標準化 自架 GitHub Actions Runner,分片就是把「一台很快的 Mac」變成能在審核者切換情境前完成 PR 驗證的機隊。若要更廣泛的建置平行度,亦可參考 CI/CD 用的平行 Mac 建置節點。
為何一台強力 Mac 仍打不到 UI 測試 SLA
Xcode 能積極平行化單元測試,但 UI 測試會耗在啟動模擬器、動畫轉場與等待 SpringBoard—這類工作在同一台主機上並不會隨 CPU 核心數線性擴展。
- 模擬器 GPU 競爭:在單一 M4 上同時跑三套 UI 套件時,影格時間常超過測試隱含假設的 33 ms 門檻,導致點擊不穩與誤判失敗。
- 磁碟放大效應:每個分片都會重複寫入 DerivedData;若沒有 500 GB 以上 SSD 餘裕,平行工作會在可用空間低於約 15% 時集體崩潰。
- 佇列不透明:沒有每分片標籤的團隊無法判斷慢 PR 是在等 UI 基礎設施還是編譯佇列—結果過度配置編譯 Runner 仍錯過 UI 截止時間。
決策矩陣:單機 Mac 與分片機隊
| 準則 | 單一 M4「包辦一切」 | 專用 UI 分片 Mac |
|---|---|---|
| 90 分鐘 UI 套件的牆鐘時間 | 序列 ≈ 90 分鐘 | 3 分片且平衡時 ≈ 35–40 分鐘 |
| 不穩定敏感度 | 過載時偏高 | 每機一套套件時較低 |
| 維運複雜度 | 低 | 中;需標籤與儀表板 |
| 最佳地理配置 | 任意 | 將分片放在港/日/韓/新/美,貼近開發者 |
採購前先為測試分桶
分片本質是排程問題偽裝成基礎設施。請將套件切成執行時間變異相近的桶—目標是每桶落在時長中位數的 ±20% 內,避免永遠同一分片當落後者。
- 匯出歷史耗時自 Xcode Cloud、XCTest 日誌或 CI 資料庫;依 p95 時長排序測試。
- 將登入密集流程獨立成桶,以免阻塞可獨立執行的結帳或設定流程。
- 需實體裝置實驗室的測試另打標—雲端 Mac mini 擅長模擬器,而非 USB 連接的硬體農場。
- 限制桶大小使每桶在 PR 預算內完成;若仍超過 25 分鐘,再依功能模組拆分。
- 將分桶對照表納入 git(
ui-shards.json)以利重跑可重現。
提示:編譯與 UI 分片請使用不同標籤。混用會在沉重的 xcodebuild test 搶走為模擬器設好逾時的 UI 機器時,造成佇列反轉意外。
UI 分片的 Runner 標籤契約
| 標籤組 | 用途 | runs-on 範例 |
|---|---|---|
| self-hosted, macOS, m4, ios-compile | 僅建置與單元測試 | [self-hosted, macOS, m4, ios-compile] |
| self-hosted, macOS, m4, ios-ui, shard-1 | UI 桶 A | [self-hosted, macOS, m4, ios-ui, shard-1] |
| self-hosted, macOS, m4, ios-ui, shard-2 | UI 桶 B | 對 B/C/D… 採相同模式 |
GitHub Actions 矩陣:避免意外重複排程
多數團隊以矩陣維度表達分片。失敗模式是同時宣告 shard: [1,2,3] 與過寬的 runs-on 標籤以致匹配每台 Mac—GitHub 可能把多個分片排在同一主機,讓硬體投資白費。請將每個矩陣分支鎖到唯一 Runner 標籤,或使用與主機名一對一的儲存庫變數。
matrix:
shard: [1, 2, 3]
include:
- shard: 1
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-1]
- shard: 2
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-2]
- shard: 3
runner_labels: [self-hosted, macOS, m4, ios-ui, shard-3]
jobs:
ui-tests:
runs-on: ${{ matrix.runner_labels }}
timeout-minutes: 40
搭配儲存庫規則,拒絕 UI 工作缺少 shard-* 標籤的流程;單一政策即可防止善意貢獻者意外壓扁平行度。當您在第二區域(例如新加坡運算搭配東京審核者)加租 Mac mini 時,請按區域複製標籤方案(shard-1-sg),讓網路鄰近在 YAML 中一目了然。
在雲端 Mac mini M4 上啟用 UI 分片的八步驟
以下假設您可透過 SSH 連線至 NodeMac 的 Mac mini M4 主機。連線方式請見 說明中心。
- 開通 N 台機器,N 等於目標分片數加 一 台熱備以應對不穩重跑。
- 預裝相同版號的 Xcode 與模擬器 runtime;分片間漂移會造成「在我的 Runner 上可以」的假陰性。
- 註冊 GitHub Runner 時使用唯一名稱,且僅掛上該分片應服務的標籤。
- 為每個工作流程設定
timeout-minutes—UI 分片可先從 40 分鐘起,再依 p95 收緊。 - 將分片識別傳入
xcodebuild(透過 scheme 或測試計畫,每桶使用-only-testing清單)。 - 關閉螢幕睡眠,若測試架構需要 GUI 工作階段則確保 CI 使用者保持登入;並依資安審查記錄政策。
- 集中上傳產物(JUnit、截圖),檔名含分片名稱以利分診。
- 分片傾斜告警:若某分片連續三次執行比其他分片慢 1.5 倍 以上,請重新平衡桶。
常見問題
一台 Mac mini M4 能容納多少個 UI 測試分片?
除非已量測到剩餘容量,否則將每個重度依賴模擬器的 UI 分片視為每台機器一個主要工作;輕量套件可嘗試兩個分片,但 GPU 與儲存競爭常會抵銷牆鐘時間的改善。
分片是否應與僅編譯工作使用相同的 Runner 標籤?
不應如此—請使用專用標籤,例如 ios-ui-shard,讓編譯工作不會搶走已額外配置模擬器與螢幕工作階段假設的機器。
若您需要距香港、東京、首爾、新加坡或美國團隊僅數分鐘路程的機器,請對照 NodeMac 方案,依上文佇列數學對齊分片數量,而非憑感覺猜測。
Mac mini M4 是 iOS UI 工作的實用分片單元:Apple Silicon 為 XCTest 編排提供強勁單執行緒效能、統一記憶體可支撐多個模擬器服務,且在 Runner 等待 PR 空檔時待機功耗低。NodeMac 出租 專用實體 Mac mini,於港、日、韓、新、美提供 SSH 與 VNC—每個分片對應可遠端除錯的真實硬體。相較買滿一整櫃 Mac,按需租用 可在驗證分片地圖與依實際遙測重新平衡時壓低資本支出。