Elixir 不穩定測試
- 完成共用 Elixir 設定以回報你的測試執行
不穩定測試係指同一份代碼多次執行時會產生唔同結果(通過或失敗)嘅測試。呢啲測試會削弱你對測試套件嘅信心,亦會浪費開發人員排查虛假失敗嘅時間。Tuist 會自動偵測不穩定測試,並幫你長期追蹤佢哋。

不穩定偵測如何運作#
Tuist 會以兩種方式偵測不穩定測試:
測試重試#
ExUnit 只會執行每個測試一次,因此間歇性失敗的測試看起來與已損壞的測試無異。啟用重試後,Hex 套件會再次執行失敗的測試,最多重試你設定的次數。如果在重試中通過,該測試會被標記為不穩定;只要所有失敗的測試最終都通過,整個執行就會成功。
預設會停用重試。在 mix.exs 的現有 Tuist 選項中加入 test_retries 以啟用:
tuist: [project: "account/project", cache: true, test_retries: 2]
或者針對單次執行,使用旗標或環境變數:
mix test --retries 2
TUIST_TEST_RETRIES=2 mix test
旗標優先於環境變數,而環境變數優先於 mix.exs。
只有失敗的測試會再次執行,方式如同 mix test --failed 執行它們;儀表板會顯示每次測試嘗試及其耗時。如果 ExUnit 因 --max-failures 而提早停止執行,則不會重試。如果失敗的測試全部逾時,也不會重試,因為每次重試都會再次等待所有逾時。使用 --warnings-as-errors 時也會略過重試,此時 mix test 不再強制執行;此外,從 umbrella 專案的根目錄執行時也會略過重試;請在 umbrella 內的其中一個應用程式中執行測試以進行重試。

跨執行偵測#
即使沒有測試重試,Tuist 仍可透過比較同一提交在不同 CI 執行中的結果來偵測不穩定測試。如果某個測試在一次 CI 執行中通過,但在同一提交與方案標籤(--scheme)的另一次執行中失敗,則該失敗的執行會被標記為不穩定。
這對於捕捉那些失敗頻率不足以被重試機制抓到、但仍會導致間歇性 CI 失敗的不穩定測試特別有用。
管理不穩定測試#
自動清除#
偵測同清除會透過項目上嘅 自動化警報 執行。每個項目都會有一個預設嘅「不穩定測試偵測」自動化,佢嘅 觸發條件 會將測試標記為不穩定,而 恢復機制 則喺測試喺設定嘅恢復期(預設 14 日)內冇再觸發之後,就會清除呢個標記。你可以喺 設定 → 自動化 入面編輯佢,去更改恢復期、更改恢復動作(例如,同時將測試從隔離中釋放),或者完全停用恢復功能,咁樣測試就會一直保持標記為不穩定,直到你手動清除佢哋。
手動管理#
你亦都可以喺測試案例詳情頁面手動標記或取消標記測試為不穩定。以下情況會有用:
- 你想喺修復問題期間確認已知嘅不穩定測試
- 由於基礎設施問題導致測試被錯誤標記
隔離不穩定測試#
隔離可防止不穩定測試在你修復期間阻礙 CI。在儀表板的測試頁面中,將其狀態改為靜音或略過,或在設定 → 自動化下設定自動化規則,讓測試在不穩定時自動靜音或略過,並在恢復後重新啟用。在執行測試前,mix test 會讀取專案中所有已隔離的測試並套用:
- 靜音:測試仍會執行且失敗仍會被回報,但如果執行中唯一的失敗來自靜音測試,則該執行視為通過。重試仍會重新執行失敗的靜音測試,因此不穩定測試可能在重試中通過並被標記為不穩定。
- 略過:測試不會執行。
mix test會在執行開始前列出被略過的測試。
Tuist: skipping 1 quarantined test:
MyApp.CheckoutTest: create_order/2 times out
Tuist: 1 muted test run, and their failures do not fail the run.
如果任何非靜音測試失敗,或 ExUnit 因 --max-failures 而提早停止,執行就會像往常一樣失敗。
- 只有較新版本的 Hex 套件才會套用隔離。較舊版本會像其他測試一樣執行靜音和略過的測試,因此靜音測試的失敗仍會導致執行失敗。在依賴此功能前,請更新
tuist_ex。 - 使用
--warnings-as-errors或從 umbrella 專案的根目錄執行時,不會套用靜音測試。此時這些測試的失敗會導致執行失敗。請改為在 umbrella 內的每個應用程式中執行測試。 - 略過是根據測試的 describe 區塊與名稱來比對,而非模組。另一個模組中具有相同 describe 區塊與名稱的測試也會被略過。請參閱略過如何選擇測試。
- 當你使用
--only、--include或path:line選取測試,或測試並非以test宣告(例如 StreamData 的property)時,被略過的測試仍會執行。 - 如果
mix test無法讀取已隔離的測試,它會執行所有測試並計算所有失敗。 - 讀取已隔離的測試需要憑證,即使是公開專案亦然。如果執行時沒有
TUIST_TOKEN、mix tuist.login工作階段或持續整合身分令牌,則不會套用任何隔離。這包括來自分叉的拉取請求,它們通常在没有密鑰的情況下執行。 - 使用
--cover時,被略過的測試會被視為移除:僅由該測試涵蓋的行會被回報為未涵蓋。
mix test 會在摘要之後列出因略過而錯誤遺漏的測試,以及仍被執行的略過測試。
略過如何選擇測試#
被略過的測試會透過基於其完整名稱的 ExUnit 篩選器排除,例如 --exclude "test:test create_order/2 times out"。ExUnit 篩選器無法同時比對模組,因此:
- 另一個模組中具有相同 describe 區塊與名稱的測試也會被排除。
mix test會在執行後列出這些測試。 - 當你使用
--only、--include或path:line選取測試時,即使該測試已被略過仍會執行,因為 ExUnit 會在排除篩選器之後套用包含篩選器。並非以test宣告的測試(例如 StreamData 的property)也是如此。mix test會在執行後列出這些測試。
再次執行已隔離的測試#
傳遞 --no-quarantine 以執行所有測試並計算所有失敗,例如用於驗證修復:
mix test --no-quarantine
在測試頁面將其狀態改回啟用,以便在後續執行中包含它。被略過的測試在再次執行之前不會產生新結果。
如果 mix test 無法讀取已隔離的測試,它會印出警告並執行所有測試(不套用隔離)。如果沒有憑證或未設定專案,它會執行所有測試且不會印出警告。
Hex 套件尚未對新測試進行壓力測試。
Slack 通知#
喺你嘅 Slack 整合中設定 不穩定測試警報,以便喺測試變得不穩定時收到通知。
查詢不穩定狀態#
資料可透過 HTTP 存取。請參閱 API 參考文件中的測試案例端點,以取得完整的路由、篩選器及回應欄位清單。若要將測試案例標記或取消標記為不穩定,請傳送帶有 is_flaky 的 PATCH /api/projects/{account_handle}/{project_handle}/tests/test-cases/{test_case_id},或使用 update_test_case Model Context Protocol 工具。