Swift Testing 並行測試不穩定時,不要先全域關閉並行:今天先固定提交、工具鏈與測試入口,隔離共享狀態和外部資源;本週再用乾淨工作區的遠端 Mac 重複執行,只有暫時無法重構的範圍才加上 .serialized。這個判斷符合 Apple 對 Swift Testing 並行執行與串行化特性的官方說明,而不是把每個紅燈都歸咎於框架行為。Swift Testing 並行執行文件
這篇文章適合三類人:正在把 XCTest 測試遷移到 Swift Testing、並發現測試順序改變後出現隨機失敗的開發者;負責遠端 Mac 測試流水線、結果採集與節點資源隔離的 DevOps 或測試工程師;以及需要決定重構、局部串行化或增加獨立節點的研發平台負責人。
最後更新於 2026 年 9 月 6 日;並行模型、.serialized 語義與測試結果處理已核對 Apple Swift Testing 官方文件、Apple Xcode 測試結果文件 與 swift-testing 官方實作。
先把「隨機失敗」拆成四種證據
本地執行通過、單獨執行失敗案例也通過,但遠端 CI 重複執行時偶爾失敗,這只能說明失敗與執行條件有關。它不等於 Swift Testing 有缺陷。你應先固定以下條件:
- 同一份提交與相同的 Xcode、Swift、macOS 工具鏈。
- 同一個測試入口,包括 Scheme、Test Plan 與命令列參數。
- 保存失敗測試、執行順序、結果包、節點記憶體壓力、硬碟空間與背景工作。
- 將失敗案例單獨執行,再與原本的並行執行結果對照。
接著把紅燈分成四類:每次都失敗的穩定錯誤;只在順序改變後失敗的狀態依賴;多個測試同時操作相同資源的競爭;以及遠端 Mac 節點本身的環境異常。這個分類決定交接對象:測試作者處理狀態,應用工程師處理資源,CI 工程師處理節點,平台負責人處理容量與隔離。
Swift Testing 的設計允許測試並行執行,也能與 XCTest 共存。Apple 的遷移文件並沒有把兩者視為同一套執行控制。因此,你要分開觀察四個層次:
- Swift Testing 在同一測試行程內的並行。
- XCTest 自身的測試並行設定。
- CI Job 同時啟動多份測試。
- 多個 Runner 共用同一台遠端 Mac。
只切換一個並行開關,不能解釋所有衝突。
02測試作者先清除共享狀態與順序依賴
遷移 XCTest 後,最容易遺留的是「前一個測試替下一個測試準備環境」。全域變數、Singleton、靜態快取與共用測試物件,在串行時可能看似正常;改成並行後,另一個測試可能在讀取中途修改同一份狀態。
你應逐項檢查:
- 測試是否讀寫同一個全域設定或靜態快取。
setUp、tearDown的替代邏輯是否真的在每個測試前後執行。- 非同步工作是否在測試結束前完成。
- 測試是否依賴另一個測試建立的資料、登入狀態或通知。
- 參數化測試的不同案例是否共用可變物件。
優先把夾具改成每個測試自行建立。測試完成時,明確取消工作、移除通知監聽並清理暫存資料。不要只在失敗後刪快取,因為刪快取可能掩蓋真正的共享狀態問題,也會改變回滾條件。
Swift Testing 為什麼只在 CI 上隨機失敗?
通常要先懷疑 CI 的執行條件,而不是先懷疑測試框架。遠端 Mac 上的測試可能與另一個 Job、背景索引工作、模擬器操作或殘留工作區同時進行。若失敗只在並行時出現,且單獨執行穩定通過,便要對照資源使用時間與測試順序。
可採用這個證據鏈:
- 固定提交、工具鏈、Scheme 與 Test Plan。
- 保存每次結果包、失敗用例與執行順序。
- 執行同一測試的單獨版本。
- 用乾淨克隆、獨立 DerivedData 與獨立暫存目錄重跑。
- 把結果與節點狀態放在同一份 CI 記錄中。
若乾淨節點仍只在並行時失敗,交給測試作者查狀態或資源。若乾淨節點通過、原工作區失敗,則先處理工作區衛生,不能直接為測試套用串行化。
03應用工程師要隔離檔案、連接埠與系統資源
固定暫存目錄是常見陷阱。兩個測試若同時建立相同資料庫檔案、讀寫相同 JSON、綁定同一個網路連接埠,結果可能由執行先後決定。UserDefaults、Keychain、通知監聽器也屬於跨測試資源,並不會因測試名稱不同而自動隔離。
修復時,讓每個測試取得自己的命名空間:
- 暫存目錄以測試識別資訊建立,測試結束後清理。
- 資料庫檔案、輸出檔案與鎖定檔使用獨立路徑。
- 網路服務使用動態連接埠,或明確分配不重疊的連接埠範圍。
- UserDefaults 使用測試專用容器,避免污染開發者帳戶。
- Keychain 測試資料使用獨立識別,結束時驗證刪除結果。
- 通知監聽器在測試結束前取消,避免下一個測試收到舊事件。
模擬器與 UI 測試要另外處理。它們可能涉及模擬器狀態、螢幕操作與外部行程,不能與進程內 Swift Testing 並行混為一談。需要 UI 或模擬器的測試,可先分到獨立 Job;但這只是隔離策略,並不代表局部串行化必然提升穩定性。
04局部使用 .serialized,不要把回退當成永久修復
Swift Testing 如何關閉部分測試的並行執行?
當證據已經指向特定 Suite、參數化測試或仍有外部共享資源的範圍,才使用 .serialized。Apple 的 ParallelizationTrait 說明確認了它用於有限範圍的串行化;它不是要求整個測試目標都停止並行的理由。
.serialized 應該加在測試函式還是 Suite 上?
判斷方式是看共享資源的範圍。如果只有一個測試需要特殊處理,將限制放在該測試或對應的參數化測試範圍;如果同一個 Suite 內的測試共同操作不可並行的資源,才放在 Suite 層級。參數化測試的行為要以當天官方文件為準,可對照 參數化測試文件,不要只按網路貼文猜測 Trait 的作用範圍。
| 決策選項 | 適用證據 | 優點 | 代價與停止條件 |
|---|---|---|---|
| 保持並行 | 乾淨工作區與共享資源檢查均通過 | 保留並行回饋速度 | 仍須持續保存失敗證據 |
Suite 或局部 .serialized |
只有特定範圍存在未隔離資源 | 控制影響面,容易回滾 | 必須記錄重構任務與移除條件 |
| 獨立遠端 Mac 節點 | 多個 Job 或模擬器資源互相爭用 | 將環境衝突與測試邏輯分開 | 增加節點管理與容量成本 |
| 全域關閉並行 | 目前無法定位失敗來源的臨時止血 | 快速降低同時衝突 | 不能作為永久結論,需安排恢復並行複核 |
每一次加入 .serialized 都應附上原因、影響範圍和回復條件。例如:「完成 Keychain 隔離並在乾淨遠端 Mac 上通過重複執行後,移除該 Trait。」如果沒有人負責驗證,臨時設定很容易變成永久技術債。
XCTest 與 Swift Testing 共存時,分開查驗設定
Swift Testing 和 XCTest 混用會影響測試並行嗎?
共存本身不等於失敗原因,但兩套框架可能由不同測試目標、Scheme 或 Test Plan 管理。你需要列出哪些測試已遷移、哪些仍由 XCTest 執行,並確認本地與 CI 是否採用相同入口。Apple 的測試目標組織文件可用來核對測試目標與專案結構。
常見誤判包括:
- 本地只執行 Swift Testing,CI 卻同時執行 XCTest。
- 本地使用一個 Test Plan,CI 使用另一個 Test Plan。
- CI 的命令列參數改變了測試選取範圍。
- 同一台遠端 Mac 上有多個 Runner 同時使用模擬器或 DerivedData。
- 遷移後保留舊有清理邏輯,造成兩套測試互相刪除資料。
先用 Apple 的 Test Plan 組織建議整理測試選取範圍,再比較每個入口的結果包。不要把所有失敗都塞進新的 Swift Testing Suite,也不要為了讓 CI 變綠而刪除原本的 XCTest 覆蓋。
06CI 工程師用遠端 Mac 重現,而不是只重跑紅燈 Job
遠端 Mac 如何重現 Swift Testing 的並發問題?
重現環境要能丟棄、能重建、能對照。先使用同一提交建立乾淨工作區,配置獨立 DerivedData 和暫存目錄;再分別執行並行版本、局部 .serialized 版本,以及單獨測試版本。每次都保存結果包、測試順序、節點記錄和工作區識別。
若你需要獨立的 macOS 測試主機,可參考 遠端 Mac CI 節點方案。選擇節點時,先確認 SSH、VNC 或網頁控制台的維運方式,再確認是否能取得完整 root 權限。若是短期調查,使用可丟棄節點比在共用開發機上反覆刪資料更容易保留證據;若要長期承接建置,再查看 Mac mini 雲端租用價格與工作區隔離方案。
你要特別記錄三類狀態:
- 測試開始前:磁碟空間、背景工作、模擬器狀態與工作區版本。
- 測試執行中:Job 數量、記憶體壓力、連接埠與檔案鎖定狀況。
- 測試結束後:結果包是否完整、暫存資料是否清除、節點是否仍有殘留行程。
刪除快取、修改 Keychain 或重建工作區前,先保存原始證據與回滾方式。否則你可能得到一次綠色結果,卻失去判斷失敗來源的資料。
07平台負責人依證據決定重構、串行或分節點
把責任邊界寫進交接單,能避免測試作者與平台團隊互相推回問題。測試作者交付共享狀態清單與重構結果;應用工程師交付檔案、連接埠、UserDefaults、Keychain 和通知資源的隔離證據;CI 工程師交付乾淨工作區與節點狀態;平台負責人則判斷是否需要獨立遠端 Mac。
可用以下條件作決策:
- 失敗穩定出現在同一測試:先修測試邏輯,不增加節點。
- 只有固定資源衝突:先隔離資源,無法立即完成時局部
.serialized。 - 多個 Job 互相影響:拆分工作區或使用獨立節點。
- 乾淨環境仍無法重現:保留並行設定,繼續補充失敗證據。
- 全域串行後變綠但原因不明:視為臨時回退,不視為驗收通過。
恢復並行前,至少要在乾淨環境重跑、重新啟動節點後複測,並確認失敗證據能追溯到測試、執行階段和資源狀態。只有「某次重跑變綠」不足以移除隔離措施。
如果你目前的電腦無法穩定重現並行問題,獨立遠端 Mac 通常比在日常工作機上反覆清理更容易控制變數。現有共用主機的缺點是工作區殘留難追、其他 Job 會爭用模擬器與連接埠,而且節點資源狀態不一定能和結果包一起保存;租用 VpsMesh 的 Mac 節點,可以用同一提交對照並行與局部串行方案,再根據證據決定修測試或調整 CI 節點。若你需要的是長期穩定重負載、實體介面或固定硬體管理,自購 Mac 仍可能更合適;若只是短期調查、遷移驗收或臨時測試容量,遠端租用會更容易按週期撤除。
本週建議動作
先不要全域關閉並行。建立一份包含提交版本、Xcode 設定、測試入口、結果包與節點狀態的失敗紀錄;接著隔離共享狀態、檔案、連接埠、Keychain 和模擬器資源。只有當問題範圍已定位、但重構尚未完成時,才對指定 Suite 使用 .serialized,並把移除條件寫入工作項目。最後在獨立遠端 Mac 上完成乾淨工作區複測,讓下一次並行恢復有可核對的依據。