T.C6 流程測試首跑抓到修復自己引入的順序 bug
T.C6 流程測試首跑抓到修復自己引入的順序 bug
修復跨服務互動 bug 後,新建的流程測試首跑就抓到修復自己引入的順序錯誤——單元測試綠燈、流程測試紅燈,紅燈才是對的。單元測試為了聚焦而繞過的路徑,正是跨服務互動 bug 藏身的地方。前情:T.C5 的修復合入後觸發了此問題。
觀察
這個系統的前端以輪詢讀取後端的事件流,把新事件轉成列印輸出;後端的「合併兩張單據」操作會重建明細、更換全部明細 id。T.C5 的修復針對後者:合併後前端要「立即刷新一次快照」,讓後續操作拿到重建後的新明細 id。修復者把刷新放在「同步單據列表」之前。
這個順序踩中輪詢的兩道機制。第一道是過濾:多店環境下,後端事件流混有其他店的資料,前端以本地單據列表為準濾掉非本店的部分。合併後的瞬間,本地列表還停在舊單據——新單據的資料被整批濾掉,刷新等於白做。第二道是差異比對:輪詢以上一輪結果為基準,只把新增的部分觸發輸出;空結果覆寫了這個基準,下一輪輪詢會把整張單據誤判為新增而重複觸發列印。
| 指標 | 值 |
|---|---|
| 單元測試結果 | 綠燈——測試把快照直接塞進資料層,繞過了過濾鏈 |
| 流程測試結果 | 首跑紅燈——斷言「快照綁定應指向新明細」失敗 |
| 根因 | 刷新與列表同步的順序顛倒;過濾鏈依賴列表的新鮮度 |
| 修復 | 先同步列表、再刷新快照;順序約束寫進編排的註解與流程測試 |
判讀
「直接塞狀態」是單元測試的合理手段,也是它的邊界。單元測試驗證「取消邏輯在快照正確時是否正確」,把快照塞進去是聚焦的做法。但「快照如何變成正確的」——輪詢、過濾、差異比對這條鏈——不在它的視野裡。順序 bug 剛好住在這條鏈上。
修復引入的 bug 比原始 bug 更難察覺。原始 bug 有使用者回報的症狀;修復引入的順序錯誤沒有立即症狀(要等到下一輪輪詢才重複列印),若沒有流程測試,它會以「偶發重複列印」的形態在生產環境出現,極難回溯。
首跑就紅是價值不是意外。流程測試的建置成本花在假後端與服務鏈的組裝上;一旦組起來,它驗證的是「多個服務對同一份資料的接力是否正確」。單元測試在結構上放掉的正是這段接力。
策略
- 狀態的「來路」也要被測到。若被測邏輯依賴某份狀態,至少要有一條測試讓狀態走真實的產生路徑(輪詢、過濾、同步),而不是全部直接塞。
- 編排順序是一種契約。「A 必須先於 B」的約束要同時存在於兩處:編排程式碼的註解(說明不可對調的原因)與流程測試的劇本(順序錯了就紅)。
- 修復也要過流程測試。針對跨服務互動的修復,合入前先在流程測試上跑一輪——修復引入的迴歸與原始 bug 同樣真實。
下一步路由
- 流程測試的地基怎麼搭 → 語意級假後端與流程測試
- 被繞過的鏈路屬於哪一層職責 → 三層定義與職責表
- 前一集:bug 為什麼漏掉 → T.C5 凍結參照失效被 stub 遮蔽