flaky 名單上反覆出現的一類:單獨執行綠燈、排進整批就紅燈的測試。這類 flaky 的根因:被測編排本身是 fire-and-forget(呼叫後不等待完成),流程測試的斷言在與它賽跑。競態本身也是資訊——它揭露了產品程式的時序特性;下文示範怎麼把這份資訊留下來。

觀察

結帳流程的收尾是一串背景動作:列印收據、同步資料、清理狀態、通知外接螢幕。主方法送出結帳請求成功後呼叫這個收尾編排,但沒有 await——主方法立刻返回,收尾在背景繼續。

流程測試在 結帳() 返回後立刻斷言「收據印了一張、結帳狀態已清除」。單獨執行這個測試檔:綠。與其他測試檔一起執行:紅——事件迴圈的排程不同,斷言跑在收尾完成之前。

指標
症狀同一條測試單跑綠、合跑紅(典型 flaky 特徵)
根因被測編排 fire-and-forget,斷言與背景收尾賽跑
修法斷言前輪詢等待終態(狀態已清除且列印計數到位),設上限次數
附帶發現設計事實記錄備查:產品上「結帳成功提示」出現時,列印與同步仍在進行

判讀

  1. flaky 的第一個提問:測試在等什麼、程式承諾了什麼。這條測試假設「方法返回=流程完成」,但程式的實際承諾是「方法返回=請求已送出」。斷言超出了被測物的承諾範圍,紅綠自然隨排程漂移。

  2. 輪詢終態而非固定延遲。加一個固定 sleep 能讓測試變綠,但那是把賽跑的起跑線挪後——排程更慢的環境(CI、低階機器)照樣輸。正確做法是輪詢「可觀察的終態」(狀態欄位、計數器),到達即斷言、超過上限次數才失敗。

  3. 競態是資訊,不只是麻煩。測試逼問出「這個方法返回時什麼還沒完成」——這個答案對產品同樣重要:如果日後有功能要在結帳後立刻依賴收尾結果(例如立刻讀取列印狀態),這裡就是陷阱。把它記錄下來,比默默繞過有價值。

策略

  1. 對 fire-and-forget 編排的測試,一律等待終態:明確列出「完成」的可觀察條件,輪詢直到滿足或超時。定界原則:上限取預期收尾時間的數倍量級、輪詢間隔遠小於上限——上限太短重回 flaky、太長把真 bug 等過去。
  2. 分辨兩種修法的適用性:能改產品(把收尾改成可等待)就改產品;不能或不該改(fire-and-forget 是刻意的 UX 決策——先解鎖畫面)就改測試的等待策略,並把時序特性記錄在案。
  3. flaky 診斷從「單跑 vs 合跑」開始:單跑綠合跑紅幾乎必然是共享狀態或時序競態,優先檢查未等待的非同步鏈。

下一步路由