iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
Software Development

AI 時代的 TDD:讓 AI 寫 Code,但不要讓它決定品質系列 第 7

Day 07:為什麼「先看紅燈」比「有沒有寫測試」更重要

  • 分享至 

  • xImage
  •  

前言:檢查有沒有寫測試,是最容易被騙過的一種檢查

「這個 PR 有沒有寫測試?」這句話幾乎是每個團隊 code review 時的標準問句。它很好回答——打開檔案清單,看有沒有多出 *.test.ts*Test.php 這類檔案,甚至可以寫一條 CI 規則自動擋掉沒有測試檔案的 PR。

但這個問題問錯了重點。「有沒有寫測試」是一個二元的、看檔案清單就能回答的問題;「這個測試有沒有先紅過」才是真正決定這份測試有沒有效力的關鍵,而這個問題沒辦法只看檔案清單回答。 一份從來沒有紅過的測試,跟一份根本不存在的測試,對專案品質的保護力是一樣的——差別只在於前者會讓人誤以為自己有安全網。

今日目標

  • 理解「有沒有測試檔案」跟「這份測試有沒有效力」是兩個完全不同的問題
  • 認識為什麼 AI 特別容易產出「從來沒紅過」的測試
  • 學會一個具體、可執行的驗證方法:故意讓實作退回錯誤版本
  • 建立「測試綠燈只是必要條件、不是充分條件」的判斷習慣
  • 回顧第一部(Day 1-7)整體想傳達的核心命題,為第二部鋪墊

為什麼「有沒有寫測試」是一個容易被騙過的檢查

想像兩種情境。情境一:工程師先寫實作,再補一份測試,測試從一開始寫出來就是綠燈——因為斷言的內容,本質上是從實作程式碼「抄」出來的預期值,兩邊永遠對得上。情境二:工程師先寫一份會失敗的測試,看著它真的紅燈,再寫實作讓它變綠。

兩種情境下,最終 PR 裡都「有測試檔案」,CI 都是綠燈,code review 的檢查清單都能打勾。但只有情境二裡的測試,曾經真正驗證過「如果實作是錯的,這份測試會不會抓到」。情境一裡的測試,從來沒有機會證明自己有這個能力——它可能真的驗證了正確的行為,也可能只是把實作的邏輯換句話說了一遍,兩者從綠燈的結果上完全看不出差別。

「有沒有寫測試」問的是一個存在性問題(存不存在),「這份測試有沒有效力」問的是一個因果性問題(實作錯了它會不會知道)——存在性問題可以靠看檔案清單回答,因果性問題只能靠實際讓它失敗過一次來回答。

AI 為什麼特別容易產出「從來沒紅過」的測試

前面幾天講過,AI 產生程式碼的模式常常是一次到位:接到一個需求,直接生成「實作 + 對應的測試」一整包。這個生成順序本身就有問題——如果 AI 是先想清楚實作邏輯、再回頭寫斷言去驗證這個邏輯,那斷言很容易變成「這段程式碼現在做了什麼,我就斷言什麼」,而不是「這段程式碼應該做什麼,我用這個標準去檢驗它」。

這兩者的差異在多數情況下看不出來,因為當實作是對的,兩種寫法產出的斷言值會一模一樣。差異只會在實作出錯的那一刻顯現——如果斷言是照著錯誤的實作抄出來的,這份測試會很盡責地跟著錯誤一起變綠。

具體的驗證方法:故意讓實作退回錯誤版本

要知道一份測試有沒有效力,不能只看它現在是不是綠燈,要主動製造一次「應該要紅」的情境,看它會不會如實反應:

❌ 只看測試現況:
「這份測試是綠燈,應該沒問題。」
→ 綠燈只告訴你「測試跟目前的實作一致」,
  沒告訴你「如果實作是錯的,測試會不會發現」

✅ 主動驗證測試的偵錯能力:
「我先把實作裡的一個判斷條件故意改錯
(例如把 >= 改成 >,或者把某個回傳值寫死),
 重新跑一次這份測試——如果它變紅了,
 代表它真的在驗證這個判斷條件;
 如果它還是綠的,代表這份測試從頭到尾
 沒有真正測到這個邏輯,只是在陪跑。」
→ 用「刻意犯錯」反向驗證測試的偵錯能力,
  這是唯一能確認測試有沒有效力的方法

這個做法在測試領域有一個對應的正式概念,叫做「突變測試」(mutation testing):工具會自動對原始程式碼做微小的變異(例如把比較運算子、邊界值、布林邏輯做小幅改動),重新跑一次測試套件,如果測試套件沒有因為這個變異而變紅,代表這個變異點沒有被有效測試涵蓋到。多數主流語言都有對應的突變測試工具(例如 PHP 生態的 Infection、JavaScript 生態的 Stryker),可以把「故意讓實作退回錯誤版本」這件事自動化、系統化地跑過整個程式碼庫,而不是只能靠人工挑幾個地方手動驗證。

但工具能自動化的是「大規模掃描」,不能取代「動手寫測試的當下,先看過一次真的紅燈」這個紀律本身——後者是在寫程式碼的過程中,對每一份測試逐一確認過的動作,前者是事後的抽查機制,兩者互補,不是取代關係。

為什麼這件事對 AI 協作特別重要

如果你只把「有沒有測試檔案」當成品質把關的標準,AI 會很快學會滿足這個標準——因為這是一個容易滿足的標準。 但這正是這個系列反覆講的模式:AI 會找到滿足檢查條件的最短路徑,而不是自動理解檢查條件背後真正想確保的事。如果團隊的把關流程只停在「檢查測試檔案存不存在」,AI(或任何工程師)會很自然地把力氣花在讓檢查通過,而不是花在確保測試真的有效力。

真正能防住這件事的,不是要求 AI「寫更多測試」,而是要求 AI 在寫每一份測試的過程中,明確交代出「我看過這份測試紅過一次」這個事實。 這件事沒辦法靠事後檢查完全補回來(除非搭配突變測試這類工具),最可靠的做法是把它變成流程的一部分——要求先寫斷言、跑一次確認失敗、再寫實作,而不是先寫完實作才回頭補測試。

第一部回顧:為什麼 AI 時代更需要 TDD

這是第一部(Day 1-7)的最後一篇。這七天想建立的核心命題是:AI 讓「產出測試程式碼」這個動作變得極快,但 TDD 真正在意的從來不是「有沒有測試程式碼」,而是「這個循環裡的每一步,有沒有真正驗證過它該驗證的事」——Red 階段驗證的是「這份測試真的能抓到錯」,Green 階段驗證的是「這個實作真的解決了問題」,Refactor 階段驗證的是「重構後行為沒有改變」。AI 可以加速每一步的產出,但沒辦法替你確認這些驗證有沒有真的發生過,這件事只能靠人在關鍵節點親自確認。

從明天開始,第二部要把焦點從「Red 階段」移到「Green 階段」——AI 在追求測試變綠的過程中,最容易走哪些捷徑。

今日思考題

回想你手上最近一份測試:如果現在故意把對應的實作邏輯改錯一個地方,你有把握這份測試會變紅嗎?如果沒有把握,你會用什麼方法確認?

今日重點回顧

  • 「有沒有寫測試」是存在性問題,看檔案清單就能回答;「測試有沒有效力」是因果性問題,只能靠讓它真的紅過一次來確認
  • AI 常見的「一次到位」生成模式,容易讓斷言變成「照抄實作邏輯」而不是「驗證該有的行為」,這種測試在實作正確時看不出差異,只在實作出錯時才會露餡
  • 具體驗證方法:故意把實作改錯,重新跑一次測試,看它會不會變紅;突變測試工具可以把這件事自動化、大規模地跑過整個程式碼庫
  • 只檢查「有沒有測試檔案」,AI 會很快學會滿足這個容易滿足的標準,而不是真正確保測試有效力
  • 第一部核心命題:AI 能加速 TDD 循環裡每一步的產出,但沒辦法替你確認每一步真正該驗證的事有沒有發生過

明日預告

明天進入第二部,focus 轉到 Green 階段:AI 在追求「讓測試通過」的過程中,最容易寫出「讓測試通過的最小手段」,而不是真正解決問題的實作——這中間的落差,比 Red 階段的問題更難被肉眼發現。


上一篇
Day 06:Red 階段——AI 容易跳過「先看到測試失敗」這一步
下一篇
Day 08:Green 階段——AI 傾向寫出「讓測試通過的最小手段」
系列文
AI 時代的 TDD:讓 AI 寫 Code,但不要讓它決定品質9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言