用測試約束 AI 改程式

說明測試如何保存已知期待、約束 Agent 後續修改,以及為什麼測試通過不等於所有問題都已被驗證。

上一篇寫到,我現在不會只接受一句:

「AI 已經做完了。」

我會用不同層次的證據確認實作。

其中一層,就是測試。

TDD 本來就是我的開發流程之一,不是功能做完之後才另外補上去的驗收步驟。

但大量把實作交給 Coding Agent 之後,我更明顯感受到測試的一個作用:

程式可以一直改,但每一次修改,都要重新面對以前留下的期待。

測試留下的不是「這版程式沒問題」

我用 Spectra 規劃實作時,通常一開始就會要求採 TDD。

也就是先把這次預期成立的行為寫清楚,再讓實作去符合它。

這和功能完成後才補一批測試有一個很重要的差別。

如果測試是在程式已經寫完之後,才根據目前的行為補上,很容易只是把現況記錄成:

「現在的程式就是這樣跑。」

但我真正希望留下的是:

「這次我們確認它應該這樣運作。」

差別看起來很小,但後面的修改一多,就會變得很重要。

後面每次修改,都要重新經過以前的測試

我最常感受到測試作用的時候,不是第一次把功能做完。

而是幾天、幾週之後,又回來改同一段功能。

新的需求進來,Codex 修改原本的程式。

這時以前留下的測試也會重新跑。

如果原本確認過的行為被改壞,測試就會失敗。

這讓後面的修改不能只顧著把新的需求做出來。

它還要重新面對:

以前已經說好不能被破壞的東西,現在還成立嗎?

對我來說,這就是測試在 AI Coding 流程裡很重要的一層約束。

測試失敗,不一定代表程式寫錯

實際開發時,我也常遇到另一種情況。

功能需求真的改了。

Codex 把新的行為做出來,但原本測試裡的斷言還停在舊版本。

結果測試失敗,CI 也過不了。

這時候不能看到紅燈就直接說:

「程式壞了。」

還要先確認:

是新的修改破壞了原本應該維持的行為?

還是這次本來就要改變那個行為?

如果需求真的改了,舊測試也應該一起更新。

所以測試不是一條永遠不能動的規則。

它更像是把目前已經確認的期待保存下來。

當行為要改時,就必須一起面對:

我們是不是也正式改變了原本的期待?

這對大量使用 Agent 的開發方式特別重要

我平常很少逐行看 Codex 修改了哪些程式,也不會人工比對每一次 patch。

所以如果沒有其他約束,很容易只看到:

新功能最後動了。

需求表面上完成了。

但底下原本的行為有沒有被一起改掉,我不一定會立刻看見。

測試提供的不是完整答案。

但它至少讓修改不是完全沒有歷史。

以前已經被確認過的行為會留在那裡,後面的程式每次改動,都要重新跟它們對照。

這也讓我不需要只靠自己的記憶去想:

「這個地方以前是不是還有一個不能壞的條件?」

有些已經被寫進測試裡的期待,會自己重新出現。

測試約束的是已經被寫下來的東西

當然,這裡有一個很明顯的限制。

測試只能檢查:

已經有人想到,並且寫成測試的東西。

沒有想到的情況,不會因為 CI 全綠就自動得到保證。

規格本身如果漏掉重要情境,測試也可能很完整地驗證一個不完整的規格。

所以我不會把「測試全部通過」理解成:

這個功能已經全面正確。

它比較像是在回答:

那些已經被明確留下來的期待,現在還有沒有成立?

這也是為什麼測試之後,我的流程還不會結束。

因為即使已知行為都成立,還有另一個問題:

功能做對了,最後的實作方式也適合這套系統嗎?