跳至內容

Elixir 不穩定測試

必要條件

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

Phoenix 應用程式的不穩定測試

不穩定偵測如何運作#

Tuist 會以兩種方式偵測不穩定測試:

測試重試#

ExUnit 只會執行每個測試一次,因此間歇性失敗的測試看起來與已損壞的測試無異。啟用重試後,Hex 套件會再次執行失敗的測試,最多重試你設定的次數。如果在重試中通過,該測試會被標記為不穩定;只要所有失敗的測試最終都通過,整個執行就會成功。

預設會停用重試。在 mix.exs 的現有 Tuist 選項中加入 test_retries 以啟用:

elixir
tuist: [project: "account/project", cache: true, test_retries: 2]

或者針對單次執行,使用旗標或環境變數:

bash
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 內的其中一個應用程式中執行測試以進行重試。

不穩定的 ExUnit 測試及其歷史記錄

跨執行偵測#

即使沒有測試重試,Tuist 仍可透過比較同一提交在不同 CI 執行中的結果來偵測不穩定測試。如果某個測試在一次 CI 執行中通過,但在同一提交與方案標籤(--scheme)的另一次執行中失敗,則該失敗的執行會被標記為不穩定。

這對於捕捉那些失敗頻率不足以被重試機制抓到、但仍會導致間歇性 CI 失敗的不穩定測試特別有用。

管理不穩定測試#

自動清除#

偵測同清除會透過項目上嘅 自動化警報 執行。每個項目都會有一個預設嘅「不穩定測試偵測」自動化,佢嘅 觸發條件 會將測試標記為不穩定,而 恢復機制 則喺測試喺設定嘅恢復期(預設 14 日)內冇再觸發之後,就會清除呢個標記。你可以喺 設定 → 自動化 入面編輯佢,去更改恢復期、更改恢復動作(例如,同時將測試從隔離中釋放),或者完全停用恢復功能,咁樣測試就會一直保持標記為不穩定,直到你手動清除佢哋。

手動管理#

你亦都可以喺測試案例詳情頁面手動標記或取消標記測試為不穩定。以下情況會有用:

  • 你想喺修復問題期間確認已知嘅不穩定測試
  • 由於基礎設施問題導致測試被錯誤標記

隔離不穩定測試#

隔離可防止不穩定測試在你修復期間阻礙 CI。在儀表板的測試頁面中,將其狀態改為靜音或略過,或在設定 → 自動化下設定自動化規則,讓測試在不穩定時自動靜音或略過,並在恢復後重新啟用。在執行測試前,mix test 會讀取專案中所有已隔離的測試並套用:

  • 靜音:測試仍會執行且失敗仍會被回報,但如果執行中唯一的失敗來自靜音測試,則該執行視為通過。重試仍會重新執行失敗的靜音測試,因此不穩定測試可能在重試中通過並被標記為不穩定。
  • 略過:測試不會執行。mix test 會在執行開始前列出被略過的測試。
plaintext
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 以執行所有測試並計算所有失敗,例如用於驗證修復:

bash
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 工具。