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 官方實作

01

先把「隨機失敗」拆成四種證據

本地執行通過、單獨執行失敗案例也通過,但遠端 CI 重複執行時偶爾失敗,這只能說明失敗與執行條件有關。它不等於 Swift Testing 有缺陷。你應先固定以下條件:

  • 同一份提交與相同的 Xcode、Swift、macOS 工具鏈。
  • 同一個測試入口,包括 Scheme、Test Plan 與命令列參數。
  • 保存失敗測試、執行順序、結果包、節點記憶體壓力、硬碟空間與背景工作。
  • 將失敗案例單獨執行,再與原本的並行執行結果對照。

接著把紅燈分成四類:每次都失敗的穩定錯誤;只在順序改變後失敗的狀態依賴;多個測試同時操作相同資源的競爭;以及遠端 Mac 節點本身的環境異常。這個分類決定交接對象:測試作者處理狀態,應用工程師處理資源,CI 工程師處理節點,平台負責人處理容量與隔離。

Swift Testing 的設計允許測試並行執行,也能與 XCTest 共存。Apple 的遷移文件並沒有把兩者視為同一套執行控制。因此,你要分開觀察四個層次:

  1. Swift Testing 在同一測試行程內的並行。
  2. XCTest 自身的測試並行設定。
  3. CI Job 同時啟動多份測試。
  4. 多個 Runner 共用同一台遠端 Mac。

只切換一個並行開關,不能解釋所有衝突。

02

測試作者先清除共享狀態與順序依賴

遷移 XCTest 後,最容易遺留的是「前一個測試替下一個測試準備環境」。全域變數、Singleton、靜態快取與共用測試物件,在串行時可能看似正常;改成並行後,另一個測試可能在讀取中途修改同一份狀態。

你應逐項檢查:

  • 測試是否讀寫同一個全域設定或靜態快取。
  • setUptearDown 的替代邏輯是否真的在每個測試前後執行。
  • 非同步工作是否在測試結束前完成。
  • 測試是否依賴另一個測試建立的資料、登入狀態或通知。
  • 參數化測試的不同案例是否共用可變物件。

優先把夾具改成每個測試自行建立。測試完成時,明確取消工作、移除通知監聽並清理暫存資料。不要只在失敗後刪快取,因為刪快取可能掩蓋真正的共享狀態問題,也會改變回滾條件。

Swift Testing 為什麼只在 CI 上隨機失敗?

通常要先懷疑 CI 的執行條件,而不是先懷疑測試框架。遠端 Mac 上的測試可能與另一個 Job、背景索引工作、模擬器操作或殘留工作區同時進行。若失敗只在並行時出現,且單獨執行穩定通過,便要對照資源使用時間與測試順序。

可採用這個證據鏈:

  1. 固定提交、工具鏈、Scheme 與 Test Plan。
  2. 保存每次結果包、失敗用例與執行順序。
  3. 執行同一測試的單獨版本。
  4. 用乾淨克隆、獨立 DerivedData 與獨立暫存目錄重跑。
  5. 把結果與節點狀態放在同一份 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。」如果沒有人負責驗證,臨時設定很容易變成永久技術債。

05

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 覆蓋。

06

CI 工程師用遠端 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 上完成乾淨工作區複測,讓下一次並行恢復有可核對的依據。