為什麼我讓 AI 寫測試,但不讓它決定測什麼

🌏 Read English Version


200 個測試全過,上線還是出 bug

那是一個週五下午。

我剛導入 Claude Code 來寫測試,效果好得不可思議。跟它說「幫我把這個模組的測試補完整」,10 分鐘後,200 個測試就生出來了。

跑 CI,全部綠燈。覆蓋率從 45% 跳到 89%。

我想:太棒了,終於可以安心上線了。

週五傍晚部署到 staging 環境,準備週一上線。

週六早上,QA 同事做 UAT 驗收時發現問題。

她把 iPhone 和預購的 AirPods 放進購物車。結帳時,系統應該只對 iPhone 打 85 折——預購商品不參與促銷,這是寫在活動規則裡的。

但系統把兩個商品都打了折。

還好是 staging 環境,沒上到 production。但如果不是 QA 同事剛好測這個情境,這個 bug 就會直接上線。

週六下午,我回頭看那 200 個測試。

搜尋「預購」:0 個結果。 搜尋「混合」:0 個結果。 搜尋「促銷排除」:0 個結果。

200 個測試,沒有一個涵蓋「一般商品 + 預購商品混合結帳」的情況。

為什麼?

因為 AI 是根據程式碼結構去猜「什麼值得測」。它看到折扣計算函數,就測了各種折扣比例。它看到購物車邏輯,就測了新增、刪除、修改數量。

但它不知道「預購商品 + 一般商品混合」是上個月客訴最多的情境。 它不知道這個促銷規則是行銷部門臨時加的,程式碼裡只有一行不起眼的 if 判斷。 它不知道這個 bug 三個月前就出過一次,只是當時沒人發現。

那天我學到一件事:問題不是 AI 寫錯了,是 AI 測的東西根本不是該測的東西。


核心框架:What vs How

這個經驗讓我重新思考 AI 測試這件事。

後來我想通了:AI 測試要分兩層。

What(測什麼)= 人決定

  • 哪些功能要測?
  • 哪些場景最重要?
  • 優先順序是什麼?
  • 上次出包的地方要不要加強?

這些問題的答案,不在程式碼裡。

在業務邏輯裡。在客訴記錄裡。在上次 incident 的 postmortem 裡。在你的腦袋裡。

AI 看不到這些。

How(怎麼測)= AI 執行

  • 測試程式怎麼寫?
  • 斷言怎麼下?
  • 邊界條件怎麼覆蓋?
  • 測試資料怎麼準備?

這些 AI 很擅長。給它明確的目標,它能寫出比你更完整的測試。

整篇文章就在講這件事:怎麼把 What 和 How 分開。


為什麼 What 不能交給 AI?

你可能會想:AI 現在這麼強,為什麼不能讓它決定測什麼?

讓我用幾個真實場景說明。

AI 看不到你的 incident 歷史

上個月,我們的結帳流程在高併發時出現 race condition。兩個請求同時進來,庫存扣了兩次,但訂單只成立一個。

這個 incident 花了我們三天修復,寫了 15 頁的 postmortem。

這些資訊在哪裡?在 Notion 裡。在 Slack 的 #incident 頻道裡。在 on-call 工程師的記憶裡。

不在程式碼裡。

所以當我請 AI「測結帳流程」,它會測正常結帳、測庫存不足、測付款失敗。

但它不會特別測「兩個請求同時結帳」,因為它不知道這裡出過事。

AI 不知道哪些功能客戶最常用

我們的產品有 50 個 API。

但看 analytics,80% 的流量集中在 5 個 API:登入、首頁、搜尋、加入購物車、結帳。

這 5 個 API 出問題,使用者馬上感受到。其他 45 個出問題,可能一週都沒人發現。

AI 不知道這個分佈。它只會根據程式碼複雜度來判斷「這個函數很複雜,應該要多測一點」。

但複雜不代表重要。那個複雜的函數可能是一個月用一次的報表匯出。

AI 看不到程式碼以外的規格

讓我說一個具體的例子。

我們的結帳 API 有一個參數叫 apply_coupon

AI 很認真地測了: – apply_coupon = true,有 coupon,成功折扣 ✓ – apply_coupon = false,不折扣 ✓ – apply_coupon = null,預設不折扣 ✓ – apply_coupon = "invalid",回傳錯誤 ✓

技術上完美。四個 case 都過了。

但它沒測到一件事:當 apply_coupon = true 但使用者帳戶裡沒有可用的 coupon 時,系統應該顯示「您目前沒有可用的優惠券」提示,而不是直接報 400 錯誤。

為什麼它沒測?

因為這個行為寫在三個月前的需求文件裡,標題是「優化結帳體驗」。PM 在裡面寫了一行:「當使用者嘗試使用不存在的優惠券時,顯示友善提示。」

這行字不在程式碼裡。不在 API 文件裡。不在任何 AI 能讀到的地方。

這就是我說的:AI 看得到程式碼,看不到業務 context。


為什麼 How 適合交給 AI?

說完 AI 的限制,來說它擅長的部分。

「怎麼測」這件事,AI 做得比人好。

API 測試:AI 的甜蜜點

問自己一個問題:如果 AI 只能幫你測一種東西,你會選什麼?

我的答案是 API 測試。

為什麼?因為 API 的特性讓它特別適合 AI:

輸入輸出明確。 Request 長什麼樣、response 應該長什麼樣,都寫在 API 文件裡。AI 不用猜。

邊界條件有規則。 必填欄位、格式驗證、長度限制——這些規則是明確的,AI 可以自動推導出所有邊界條件。

成功失敗判斷清楚。 200 就是成功,400 就是 client 錯誤,500 就是 server 錯誤。不存在「有點成功」這種模糊地帶。

我的經驗:API 測試交給 AI,幾乎不用改。

我會跟它說:「這是我們的 User API,測 CRUD 和權限驗證。」

它會產出: – 正常 CRUD 流程 – 必填欄位缺失 – 格式錯誤(email 格式、電話格式) – 權限不足(一般使用者試圖刪除別人的資料) – 邊界條件(名字 256 字元、超長 email)

這些 case,人寫要 2 小時。AI 寫只要 5 分鐘。而且它不會漏,因為它是系統性地推導。

單元測試:需要給 context

單元測試比 API 測試難一點。

因為 AI 需要理解「這個函數為什麼存在」。

舉個例子。我們有一個函數叫 calculateDiscount()

AI 看到這個函數,會測: – 輸入 100,折扣 10%,輸出 90 ✓ – 輸入 0,輸出 0 ✓ – 輸入負數,丟出錯誤 ✓

技術上正確。但沒有業務意義。

因為這個函數真正的複雜度在於: – VIP 客戶有額外 5% 折扣 – 週年慶期間全館再 85 折 – 但 VIP 折扣和週年慶折扣不能疊加 – 除非是黑卡會員,可以疊加 – 但黑卡會員如果是員工,就不能用員工價又用黑卡折扣

這些規則 AI 不知道。

所以我會先跟它說:

「這個函數計算訂單折扣。有以下規則: 1. 基本折扣根據 promotionType 決定 2. VIP 會員額外 5% 3. VIP 折扣和活動折扣不疊加,取高者 4. 黑卡會員例外,可以疊加 5. 員工不能同時用員工價和會員折扣

請針對這些規則寫測試。」

給了 context,AI 產出的測試就從「技術正確」變成「業務有意義」。

E2E 測試:一定要拆分

E2E 測試是最容易踩坑的地方。

我第一次請 AI 寫 E2E 測試,跟它說:「測整個購物流程,從登入到結帳。」

它產出了一個 500 行的測試檔案。

問題來了: – 登入、瀏覽、加入購物車、結帳,全部混在一起 – 一下測正常流程,一下測庫存不足,一下又跳回正常流程測不同付款方式 – 我光是讀懂這個測試就花了 30 分鐘

更慘的是維護。兩週後,登入流程改了,這個 500 行的測試有 47 個地方要改。

後來我學乖了:拆分。

  • 登入流程 → login.spec.ts
  • 商品瀏覽 → browse.spec.ts
  • 購物車操作 → cart.spec.ts
  • 結帳流程 → checkout.spec.ts

每個檔案請 AI 分開寫。每次只給它一個明確範圍。

結果?每個測試檔案都很清楚,維護的時候也只需要改對應的檔案。

更重要的是:邏輯差異大的場景,絕對不要放在同一批。

我曾經請 AI 同時寫「正常結帳流程」和「各種錯誤情況的處理」。

結果測試變成這樣:

1. 測試正常結帳
2. 測試信用卡過期
3. 測試正常結帳但換一種付款方式
4. 測試餘額不足
5. 測試正常結帳但用不同折扣碼
6. 測試 API timeout

正常和異常交錯,根本沒辦法讀。

現在我會分開: – 先請 AI 寫正常流程的所有變化(不同付款方式、不同折扣碼、不同運送方式) – 確認沒問題後,再請它寫異常處理(付款失敗、庫存不足、API 錯誤)

兩批測試邏輯清楚,維護也容易。


怎麼把 What 和 How 分開?

知道原則不夠,要能執行。

第一步:在請 AI 寫測試之前,先列「關鍵場景清單」

這是人的工作。

問自己: – 這個模組最重要的 3 個場景是什麼? – 上次出包的地方是哪裡? – 客戶最常用的功能是什麼? – 如果只能測 5 個東西,我會測哪 5 個?

把答案寫下來。

像這樣:

結帳模組關鍵場景:
1. 正常結帳(信用卡)- 最常見的付款方式,佔 70% 訂單
2. 一般商品 + 預購商品混合 - 上個月客訴 3 次
3. VIP 折扣計算 - 複雜規則,容易出錯
4. 高併發下的庫存扣減 - 上次 incident 的地方
5. 結帳中途 session 過期 - 使用者常反映的 UX 問題

這就是你的「What」。這個清單上的東西,一定要有測試覆蓋。

第二步:拆分工作,一次給 AI 一個明確範圍

不要說:「幫我寫結帳模組的測試。」

要說:

「幫我寫結帳 API 的測試,情境是『一般商品 + 預購商品混合結帳』。

預購商品不能參與促銷折扣。 一般商品可以用 coupon。

請測試以下情況: 1. 只有一般商品,套用 coupon 2. 只有預購商品,不能套用 coupon 3. 混合商品,只有一般商品被折扣 4. 混合商品,coupon 金額超過一般商品總額的情況」

範圍明確,AI 就不用猜。產出的測試會精準很多。

第三步:反饋要具體到 AI 不用猜

AI 寫的測試有問題,很正常。關鍵是怎麼給反饋。

壞的反饋: > 「這個測試不對,重寫。」

AI 會問:哪裡不對?它不知道,只能猜。猜錯的機率很高。

好的反饋: > 「第 23 行的斷言有問題。預期的折扣金額應該是 85,不是 80。 > 因為 VIP 折扣是 15%,100 × 0.85 = 85。 > 另外請加一個 case:VIP + 週年慶折扣不能疊加,應該取較高的那個。」

具體到 AI 不用猜,它就能一次改對。

我自己的經驗:模糊反饋一次,AI 會來回 3-4 次才改對。具體反饋一次,通常第二次就對了。


怎麼驗收 AI 的驗收?

這是 Tech Lead 和 QA Lead 最常問我的問題。

「AI 說測試通過了,我敢信嗎?」

答案是:要看你驗收了什麼。

驗收的三個層次

讓我用一個例子說明。

假設 AI 幫你的結帳模組寫了 50 個測試,全部通過。

層次 1:測試有沒有跑過

CI 跑了嗎?全部綠燈嗎?有沒有 flaky test?

這是最基本的。這一層可以完全自動化,不需要人。

但「跑過」不代表「測對」。

層次 2:測試有沒有測對東西

打開那 50 個測試,看一下:

  • 斷言是對的嗎?(確認金額是 100,但 100 這個數字對嗎?)
  • 測的是這個函數「應該做的事」嗎?(還是只測了它「做了什麼事」?)
  • 邊界條件有覆蓋嗎?(0 元、負數、超大金額)

這一層需要「懂程式」的人來 review。

我的經驗:花 15 分鐘 review AI 寫的測試,可以省 3 小時 debug。

層次 3:測試有沒有涵蓋業務關鍵路徑

回去看你的「關鍵場景清單」:

  • 「一般商品 + 預購商品混合」有測到嗎?
  • 「高併發庫存扣減」有測到嗎?
  • 「VIP 折扣計算」有測到嗎?

就算那 50 個測試技術上都正確,如果沒有覆蓋這些關鍵場景,測試還是不及格。

這一層需要「懂業務」的人來判斷。

實際流程

我現在的做法:

  1. 人定義關鍵場景清單(What)
  2. 拆分工作,分批請 AI 寫(控制範圍)
  3. Review AI 寫的測試(確認 How 正確)
  4. 對照關鍵場景清單(確認 What 有被覆蓋)
  5. 跑測試(AI 執行)
  6. 最終判斷:能不能上線(人決定)

第 1 步和第 6 步,一定是人做決定。

中間的步驟,人機協作。


這不只是測試的問題

寫到這裡,我想說一件更大的事。

這篇文章講的是 AI 測試,但背後的問題更普遍:

什麼該讓 AI 做?什麼該自己做?邊界在哪裡?

測試只是一個案例。答案是:What 留給人,How 交給 AI。

這個框架可以套用到很多地方:

寫程式: – What = 寫什麼功能、解決什麼問題 → 人決定 – How = 怎麼實作、程式碼怎麼寫 → 可以讓 AI 幫忙

寫文件: – What = 寫給誰看、要傳達什麼訊息 → 人決定 – How = 怎麼組織段落、怎麼遣詞用句 → 可以讓 AI 幫忙

做決策: – What = 要不要做這件事、優先順序是什麼 → 人決定 – How = 怎麼執行、步驟是什麼 → 可以讓 AI 幫忙

AI 時代的核心能力,不是會用 AI。

是知道什麼時候用、什麼時候不用。

這就是判斷力。

而判斷力,只能靠你自己累積。

Leave a Comment