AI 幫你寫的測試全綠,為什麼上線還是壞掉?

871 支測試全綠,卻連畫面被彈窗擋死兩天都抓不到。這篇順著我們踩過的坑,拆開 AI 假測試的長相、怎麼親眼驗出測試有沒有用,並附上一份可直接貼給 AI 的體檢 Prompt。

這篇的段落(5)
  1. 測試明明寫了八百多支,為什麼連畫面壞掉都抓不到?
  2. 那我叫 AI 把假測試刪掉重寫,總可以了吧?
  3. 測試都改對了,為什麼每次推程式碼還是要等十幾分鐘?
  4. 寫了九份原則文件叫 AI 別再犯,為什麼它讀完照樣寫錯?
  5. 看到測試全綠,現在就能拿去考 AI 的體檢指令

用 AI 寫程式一段時間之後,多數人都會養出一個好習慣:別只聽它說「改好了」,要叫它補測試、看綠燈。但 AI 寫出來的綠燈也會騙人,而且騙得比沒寫測試還徹底。

10 月中,我請 AI 在自己的即時互動教學系統加一個小功能:學生第一次輸入名字加入課堂時,畫面先彈出一張四位數「找回碼」小卡讓他存成圖片。功能寫好後我按下 git push,本機幾百支測試全部綠燈。

結果合併上線才發現,「老師開課+學生加入」的核心流程,早就因為那張新彈窗擋在畫面正中央而卡死兩天。那時專案帳面上有 871 支測試、三十多道檢查關卡,每次推送要等十幾分鐘,卻連最基本的「畫面被彈窗擋死」都沒抓到。

我叫 AI 全部停下來,把整條驗證流程砍掉重練。下面順著我們一路追問的順序,拆開這座假安心系統是怎麼長出來的,以及怎麼把它清乾淨。


測試明明寫了八百多支,為什麼連畫面壞掉都抓不到?

因為 AI 為了省事,根本沒把畫面跑起來,只是把原始碼當純文字讀進來找變數名。

當我回頭去查那支「守色彩對比度」的單元測試為什麼沒叫,才發現它從頭到尾沒有算過半個顏色,只是用正規表示式檢查檔案裡有沒有寫 --text-muted 這個字串。你叫 AI「幫這個功能補測試」卻沒限制寫法時,它最愛直接寫這兩行:

程式碼
const source = fs.readFileSync('src/features/reset.ts', 'utf8');
expect(source).toMatch(/reset_project_data_v2/);

這種測試跑起來只要 0.01 秒,永遠不會因為環境問題失敗,但它守的是檔案裡的字,跟使用者看到的功能毫無關係。我們一盤點,八百多支裡竟然有一百三十多支在幹這件事(另外還有在測試檔裡自己抄一份簡化邏輯測自己的「抄本測試」,以及檢查幾個月前早就刪掉的舊錯誤文案)。

同一個壞掉的產品,字串測試照亮綠燈放行,行為測試當場亮紅燈攔截 產品功能壞掉 if (true) return; 重設按鈕按了沒反應 AI 偷懶寫的「字串測試」 readFileSync() 找函式名 🟢 照亮綠燈(假安心) 字還在,壞程式碼放行上線 真實「行為測試」 點擊按鈕 → 檢查 API 請求 🔴 亮紅燈當場攔截 請求沒送出,擋下故障
讀原始碼比對字串的測試只管「檔案裡有沒有那個字」,功能壞了照樣綠燈;只有實際觸發行為的測試才抓得到故障。

那我叫 AI 把假測試刪掉重寫,總可以了吧?

直接叫它刪更危險,因為它連「別處已經測過了」都會看走眼。

清理第一天,AI 讀完程式碼跟我回報:「A 測試跟 B 測試重複了,B 已經完整覆蓋,所以我把 A 刪掉,測試全綠!」我不放心,手動把產品裡「儲存投影片樣式」的那行邏輯故意改壞,再跑一次測試。結果全專案一片綠燈,只有它剛才想刪掉的那支 A 測試會亮紅燈。原來 B 測試在畫面掛載後還沒等事件綁定好就急著點按鈕,從頭到尾都在測空氣。

所以我們立下一條死規矩:不聽 AI 口頭保證,想刪改任何測試,必須先通過下面的破壞驗證(Break-Check):

破壞驗證(Break-Check)四步閘門:故意改壞產品碼,親眼看接手測試亮紅燈才准刪 ① AI 想刪 A 測試 宣稱「B 已覆蓋」 ② 故意改壞產品碼 把 A 守的功能註解掉 ③ 只跑 B 測試 看 B 會不會叫? B 亮紅燈 → 准刪 A 還原產品碼確認全綠 B 仍綠燈 → 不准刪 B 在測空氣,先補保護
不信 AI 的口頭「已覆蓋」:先故意改壞產品,親眼看到接手的測試亮紅燈,才准動刀刪舊測試。

清完假測試後,我們還反過來抽考剩下的測試:不碰測試檔,隨機挑幾十個業務邏輯故意改壞(反轉分數判斷、拿掉權限檢查、關掉快取過期),結果抓出二十幾個只測成功路徑、沒測權限拒絕的漏網之魚,全數補到會亮紅燈為止。


測試都改對了,為什麼每次推程式碼還是要等十幾分鐘?

因為本機、PR 跟合併後這三道關卡一直在重複跑同一批慢檢查,真正會抓出線上故障的雙端測試卻拖到合併後才跑。

以前不管改兩行字還是改幾百個檔案,本機推送前都要跑完整打包與全套測試;推上 PR 後雲端從頭再跑第二遍;等合併進主線,才第一次去跑最核心的雙端互動流程。我們定了一條新原則,同一件事只跑一次,把真後端測試前移到 PR 階段,直接看下面的時間長條比例就能看出等待時間與攔截點的差距。

重整前後推送管線的耗時長條比例與故障攔截點對比 推送驗證管線的時間比例對照:砍掉重複慢檢查,把真故障攔截點前移到 PR ❌ 重整前:總耗時 20+ 分鐘(重工 2~3 遍),核心雙端故障卻漏到合併後才爆 1. 本機 pre-push:10+ 分鐘 全套測試+完整打包+重灌 DB 2. PR CI:7~10 分鐘 本機跑過的再重跑+重複打包 5 次 3. 合併後才測雙端 💥 壞兩天沒人發現 ✅ 重整後:總耗時 2~3 分鐘(省下 85% 等待),壞程式碼在 PR 當場攔下 本機 20 秒 秒級型別/Lint PR CI:1~3 分鐘 🛡️ 攔截點 打包 1 次+真後端雙端互動測試 合併 1 分鐘 沿用綠燈直上 ← 省下的 17 分鐘重複等待時間 小改動隨時敢推,不再憋成巨型 PR
長條寬度直接對應等待時間:把重複打包與重跑砍掉後,整條管線縮短到 3 分鐘內,且真後端雙端測試前移到 PR 階段當場攔截。

通道變快之後,我們順手清查了以前因為「跑太慢」被移出自動名單的二十多支孤兒瀏覽器測試。把不依賴真實排版的案例降到記憶體裡跑、剩下的孤兒重新排進 PR 自動關卡後,第一輪就爆出十個紅燈,全數抓到開頭說的那張找回碼彈窗。留在專案裡的測試,要嘛每輪自動跑,要嘛驗證後刪掉;躺在角落不跑的測試只會默默腐爛。


寫了九份原則文件叫 AI 別再犯,為什麼它讀完照樣寫錯?

因為寫在 Markdown 裡的規定對 AI 來說只是參考,只有編譯器跟靜態檢查畫的紅線它才繞不過去。

我們原本有九份近千行的原則文件,白紙黑字寫著「不要亂傳 ID」「不要寫讀原始碼的測試」,但 AI 讀完轉頭照犯。與其寫文件拜託 AI 記住,我們直接把規則沿著下面的五層階梯往上搬,讓錯的程式碼在存檔或推送那一刻就被工具擋死:

五層約束階梯:越往上搬,攔截速度越快、越不靠人與 AI 記憶 把文字規定往上搬成硬約束:越高層擋得越早,越不需要 AI「記得遵守」 ① 架構消除:移除危險入口,Store 外部唯讀 ⚡ 錯誤根本寫不出來 ② 編譯期型別:6 種 ID 貼互斥標籤(Branded Types) ⏱️ 存檔 0.1 秒拒收 ③ 語法樹與依賴圖:ESLint 禁讀原始碼、鎖單向依賴 ⏱️ 推送前 3 秒攔截 ④ 行為測試:通過破壞驗證的業務與雙端互動測試 ⏱️ PR 1~3 分鐘攔截 ⑤ 純文字提醒:寫在 CLAUDE.md / AGENTS.md 的口頭規定 ❌ 0 攔截(讀完照忘)
寫過第二次的第 ⑤ 層文字提醒,就該沿左側箭頭往上搬成第 ①~③ 層的自動紅線;把六種 ID 換成型別標籤後,傳錯參數存檔即報錯,十幾支防呆測試當場退役。

看到測試全綠,現在就能拿去考 AI 的體檢指令

下次看到測試一片綠燈,先問三個問題:把功能故意改壞一行會不會紅?這支測試有沒有在每次 PR 自動跑?這條規定能不能往上搬進型別或 ESLint?

如果你想讓 AI 幫你把專案裡的假測試、重複慢關卡與肥大規則檔清一遍,直接把下面這段體檢指令貼給 Claude Code、Cursor 或 Codex(第一輪先讓它交唯讀診斷報告,確認清單後再動手):

程式碼
請對這個專案進行「測試真實性、CI 管線耗時與型別約束」唯讀體檢(先不要修改任何檔案),交出以下 4 份清單:

1. 假測試名單:找出所有用 readFileSync 讀原始碼比對字串、在測試裡重抄產品邏輯測自己、或斷言舊文案不存在的測試檔,逐支標註建議「改為行為測試」或「轉成 ESLint 規則後淘汰」。
2. 孤兒測試與慢關卡對照:列出本機 pre-push、PR CI、合併後各自跑了哪些指令與耗時,標出重複跑了兩遍以上的檢查,以及躺在目錄裡卻沒排進 PR 自動執行的孤兒測試。
3. 可升級為硬約束的規則:讀完 CLAUDE.md / AGENTS.md,挑出哪些文字規定可以直接升級成 Branded Types、集中註冊表、ESLint AST 規則或 dependency-cruiser 單向依賴鎖。
4. 分批改造計畫:每一批刪除或改寫測試前,必須先執行破壞驗證(故意改壞對應產品碼 → 證明接手測試亮紅燈 → 還原確認全綠),請列出第一批最值得動刀的 5 個檔案。

拿到清單後,挑最痛的一批開始,親眼看到紅燈再放行。如果還不確定自己的專案最該先修哪一層,可以先做免費的 AI 工作流五層健檢,照題目、資料、工具、進度、驗收五個問題找出最划算的修法;想看我們怎麼在連半行原始碼都沒有的老系統裡做雙端反組譯對帳,也可以接著讀〈帶著 AI 把 2012 年的無原始碼老遊戲從零救活:多模型逆向除錯與本機 v1.0.0 優化實錄〉與〈Claude Code 實戰:我怎麼用 AI 寫完一整個網站〉。

免費 5 層健檢:拿手上的任務自己測 →看 Claude Code 深度工程手冊(免費試看) →60 分鐘專案卡關諮詢 →
Cab(CabLate)作者照片

寫這篇的是 Cab,在第一線教 AI 落地,從農會推廣人員教到外商工程團隊。我的經歷・團隊想導入,看企業內訓。