「這個 PR 有沒有寫測試?」這句話幾乎是每個團隊 code review 時的標準問句。它很好回答——打開檔案清單,看有沒有多出 *.test.ts、*Test.php 這類檔案,甚至可以寫一條 CI 規則自動擋掉沒有測試檔案的 PR。
但這個問題問錯了重點。「有沒有寫測試」是一個二元的、看檔案清單就能回答的問題;「這個測試有沒有先紅過」才是真正決定這份測試有沒有效力的關鍵,而這個問題沒辦法只看檔案清單回答。 一份從來沒有紅過的測試,跟一份根本不存在的測試,對專案品質的保護力是一樣的——差別只在於前者會讓人誤以為自己有安全網。
想像兩種情境。情境一:工程師先寫實作,再補一份測試,測試從一開始寫出來就是綠燈——因為斷言的內容,本質上是從實作程式碼「抄」出來的預期值,兩邊永遠對得上。情境二:工程師先寫一份會失敗的測試,看著它真的紅燈,再寫實作讓它變綠。
兩種情境下,最終 PR 裡都「有測試檔案」,CI 都是綠燈,code review 的檢查清單都能打勾。但只有情境二裡的測試,曾經真正驗證過「如果實作是錯的,這份測試會不會抓到」。情境一裡的測試,從來沒有機會證明自己有這個能力——它可能真的驗證了正確的行為,也可能只是把實作的邏輯換句話說了一遍,兩者從綠燈的結果上完全看不出差別。
「有沒有寫測試」問的是一個存在性問題(存不存在),「這份測試有沒有效力」問的是一個因果性問題(實作錯了它會不會知道)——存在性問題可以靠看檔案清單回答,因果性問題只能靠實際讓它失敗過一次來回答。
前面幾天講過,AI 產生程式碼的模式常常是一次到位:接到一個需求,直接生成「實作 + 對應的測試」一整包。這個生成順序本身就有問題——如果 AI 是先想清楚實作邏輯、再回頭寫斷言去驗證這個邏輯,那斷言很容易變成「這段程式碼現在做了什麼,我就斷言什麼」,而不是「這段程式碼應該做什麼,我用這個標準去檢驗它」。
這兩者的差異在多數情況下看不出來,因為當實作是對的,兩種寫法產出的斷言值會一模一樣。差異只會在實作出錯的那一刻顯現——如果斷言是照著錯誤的實作抄出來的,這份測試會很盡責地跟著錯誤一起變綠。
要知道一份測試有沒有效力,不能只看它現在是不是綠燈,要主動製造一次「應該要紅」的情境,看它會不會如實反應:
❌ 只看測試現況:
「這份測試是綠燈,應該沒問題。」
→ 綠燈只告訴你「測試跟目前的實作一致」,
沒告訴你「如果實作是錯的,測試會不會發現」
✅ 主動驗證測試的偵錯能力:
「我先把實作裡的一個判斷條件故意改錯
(例如把 >= 改成 >,或者把某個回傳值寫死),
重新跑一次這份測試——如果它變紅了,
代表它真的在驗證這個判斷條件;
如果它還是綠的,代表這份測試從頭到尾
沒有真正測到這個邏輯,只是在陪跑。」
→ 用「刻意犯錯」反向驗證測試的偵錯能力,
這是唯一能確認測試有沒有效力的方法
這個做法在測試領域有一個對應的正式概念,叫做「突變測試」(mutation testing):工具會自動對原始程式碼做微小的變異(例如把比較運算子、邊界值、布林邏輯做小幅改動),重新跑一次測試套件,如果測試套件沒有因為這個變異而變紅,代表這個變異點沒有被有效測試涵蓋到。多數主流語言都有對應的突變測試工具(例如 PHP 生態的 Infection、JavaScript 生態的 Stryker),可以把「故意讓實作退回錯誤版本」這件事自動化、系統化地跑過整個程式碼庫,而不是只能靠人工挑幾個地方手動驗證。
但工具能自動化的是「大規模掃描」,不能取代「動手寫測試的當下,先看過一次真的紅燈」這個紀律本身——後者是在寫程式碼的過程中,對每一份測試逐一確認過的動作,前者是事後的抽查機制,兩者互補,不是取代關係。
如果你只把「有沒有測試檔案」當成品質把關的標準,AI 會很快學會滿足這個標準——因為這是一個容易滿足的標準。 但這正是這個系列反覆講的模式:AI 會找到滿足檢查條件的最短路徑,而不是自動理解檢查條件背後真正想確保的事。如果團隊的把關流程只停在「檢查測試檔案存不存在」,AI(或任何工程師)會很自然地把力氣花在讓檢查通過,而不是花在確保測試真的有效力。
真正能防住這件事的,不是要求 AI「寫更多測試」,而是要求 AI 在寫每一份測試的過程中,明確交代出「我看過這份測試紅過一次」這個事實。 這件事沒辦法靠事後檢查完全補回來(除非搭配突變測試這類工具),最可靠的做法是把它變成流程的一部分——要求先寫斷言、跑一次確認失敗、再寫實作,而不是先寫完實作才回頭補測試。
這是第一部(Day 1-7)的最後一篇。這七天想建立的核心命題是:AI 讓「產出測試程式碼」這個動作變得極快,但 TDD 真正在意的從來不是「有沒有測試程式碼」,而是「這個循環裡的每一步,有沒有真正驗證過它該驗證的事」——Red 階段驗證的是「這份測試真的能抓到錯」,Green 階段驗證的是「這個實作真的解決了問題」,Refactor 階段驗證的是「重構後行為沒有改變」。AI 可以加速每一步的產出,但沒辦法替你確認這些驗證有沒有真的發生過,這件事只能靠人在關鍵節點親自確認。
從明天開始,第二部要把焦點從「Red 階段」移到「Green 階段」——AI 在追求測試變綠的過程中,最容易走哪些捷徑。
回想你手上最近一份測試:如果現在故意把對應的實作邏輯改錯一個地方,你有把握這份測試會變紅嗎?如果沒有把握,你會用什麼方法確認?
明天進入第二部,focus 轉到 Green 階段:AI 在追求「讓測試通過」的過程中,最容易寫出「讓測試通過的最小手段」,而不是真正解決問題的實作——這中間的落差,比 Red 階段的問題更難被肉眼發現。