用測試約束 AI 改程式
說明測試如何保存已知期待、約束 Agent 後續修改,以及為什麼測試通過不等於所有問題都已被驗證。
上一篇寫到,我現在不會只接受一句:
「AI 已經做完了。」
我會用不同層次的證據確認實作。
其中一層,就是測試。
TDD 本來就是我的開發流程之一,不是功能做完之後才另外補上去的驗收步驟。
但大量把實作交給 Coding Agent 之後,我更明顯感受到測試的一個作用:
程式可以一直改,但每一次修改,都要重新面對以前留下的期待。
測試留下的不是「這版程式沒問題」
我用 Spectra 規劃實作時,通常一開始就會要求採 TDD。
也就是先把這次預期成立的行為寫清楚,再讓實作去符合它。
這和功能完成後才補一批測試有一個很重要的差別。
如果測試是在程式已經寫完之後,才根據目前的行為補上,很容易只是把現況記錄成:
「現在的程式就是這樣跑。」
但我真正希望留下的是:
「這次我們確認它應該這樣運作。」
差別看起來很小,但後面的修改一多,就會變得很重要。
後面每次修改,都要重新經過以前的測試
我最常感受到測試作用的時候,不是第一次把功能做完。
而是幾天、幾週之後,又回來改同一段功能。
新的需求進來,Codex 修改原本的程式。
這時以前留下的測試也會重新跑。
如果原本確認過的行為被改壞,測試就會失敗。
這讓後面的修改不能只顧著把新的需求做出來。
它還要重新面對:
以前已經說好不能被破壞的東西,現在還成立嗎?
對我來說,這就是測試在 AI Coding 流程裡很重要的一層約束。
測試失敗,不一定代表程式寫錯
實際開發時,我也常遇到另一種情況。
功能需求真的改了。
Codex 把新的行為做出來,但原本測試裡的斷言還停在舊版本。
結果測試失敗,CI 也過不了。
這時候不能看到紅燈就直接說:
「程式壞了。」
還要先確認:
是新的修改破壞了原本應該維持的行為?
還是這次本來就要改變那個行為?
如果需求真的改了,舊測試也應該一起更新。
所以測試不是一條永遠不能動的規則。
它更像是把目前已經確認的期待保存下來。
當行為要改時,就必須一起面對:
我們是不是也正式改變了原本的期待?
這對大量使用 Agent 的開發方式特別重要
我平常很少逐行看 Codex 修改了哪些程式,也不會人工比對每一次 patch。
所以如果沒有其他約束,很容易只看到:
新功能最後動了。
需求表面上完成了。
但底下原本的行為有沒有被一起改掉,我不一定會立刻看見。
測試提供的不是完整答案。
但它至少讓修改不是完全沒有歷史。
以前已經被確認過的行為會留在那裡,後面的程式每次改動,都要重新跟它們對照。
這也讓我不需要只靠自己的記憶去想:
「這個地方以前是不是還有一個不能壞的條件?」
有些已經被寫進測試裡的期待,會自己重新出現。
測試約束的是已經被寫下來的東西
當然,這裡有一個很明顯的限制。
測試只能檢查:
已經有人想到,並且寫成測試的東西。
沒有想到的情況,不會因為 CI 全綠就自動得到保證。
規格本身如果漏掉重要情境,測試也可能很完整地驗證一個不完整的規格。
所以我不會把「測試全部通過」理解成:
這個功能已經全面正確。
它比較像是在回答:
那些已經被明確留下來的期待,現在還有沒有成立?
這也是為什麼測試之後,我的流程還不會結束。
因為即使已知行為都成立,還有另一個問題:
功能做對了,最後的實作方式也適合這套系統嗎?