iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
Software Development

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

Day 15:邊界情境——AI 容易只測 happy path,例外情境要人主動要求

  • 分享至 

  • xImage
  •  

前言:測試都寫了,為什麼上線後還是被邊界案例絆倒?

「我讓 AI 幫這個函式補了測試,涵蓋率也不低,怎麼上線後第一週就被一個空陣列輸入搞掛了?」

這是我接手一套系統、開始要求所有新功能都要有 AI 協作寫測試之後,最常聽到的抱怨。追查下去會發現一個規律:AI 幫忙寫的測試幾乎都精準命中「這個函式在正常情況下該怎麼運作」,卻很少主動涵蓋「如果輸入是空的、是負數、是超長字串、或是兩個請求同時打進來會怎樣」這類邊界情境。

這不是 AI 偷懶,而是AI 預設會生成的測試,幾乎都是從需求描述裡最直接能推導出來的情境——也就是 happy path。邊界案例往往不在需求描述裡明講,它們藏在「如果 XXX 沒有寫清楚會怎樣」這種隱性假設裡,而隱性假設正是 AI 最難自己補上的部分。

今日目標

  • 理解為什麼 AI 生成測試時天然偏向 happy path,這不是能力問題而是資訊來源問題
  • 認識邊界情境的幾個常見類別,建立一份可以拿來對照的檢查清單
  • 學會用具體的 prompt 設計,強迫 AI 先把邊界情境攤開來,而不是直接跳去寫測試
  • 建立「happy path 測試只是起點,不是終點」的判斷習慣

為什麼 AI 天然只測 happy path

AI 生成測試時依賴的輸入,主要是函式簽章、文件字串、還有你給的需求描述。這些東西描述的幾乎都是「這個函式正常情況下該做什麼」——例如「輸入一個訂單,計算總金額」。這句話本身沒有告訴 AI:訂單裡的商品列表可以是空的嗎?金額可以是負數嗎?同一個訂單 ID 被重複呼叫會不會出問題?

這些邊界情境不是需求描述裡「漏講」的細節,而是需求描述這種載體本身的侷限——正常流程可以用一句話講完,例外情境卻要靠對這個領域的實際經驗才想得到。 AI 沒有那個實際踩過坑的經驗,它只能忠實反映你給它的輸入裡有的資訊,而正常情況下的資訊,永遠比邊界情況的資訊更容易被清楚地寫出來。

用一組對照來看這個差異:

❌ 只描述 happy path 的需求,AI 生成對應的測試:
「寫一個函式,計算購物車裡所有商品的總金額。」

test('calculateTotal_輸入正常商品清單_回傳正確總金額', () => {
  const items = [{ price: 100, qty: 2 }, { price: 50, qty: 1 }];
  expect(calculateTotal(items)).toBe(250);
});
→ 只驗證了「正常輸入下算得對」,
  完全沒觸及空陣列、負數、超大數字、qty 為 0 這些情境

✅ 先明講邊界情境要求,AI 才會涵蓋:
「寫一個函式,計算購物車裡所有商品的總金額。
 請先列出這個函式可能遇到的邊界情境(空輸入、極端值、
 型別異常等),我確認過後再開始寫對應的測試。」

// AI 列出的邊界情境清單(人審過再動手):
// - 空陣列:總金額應為 0
// - price 或 qty 為負數:該拒絕還是視為 0?
// - qty 為 0:該計入清單還是視為無效項目?
// - 數字精度:price 是浮點數時會不會有精度誤差?
→ 邊界情境先被攤開來討論,哪些該測、該怎麼處理,
  由人確認過才動手,而不是事後才發現漏了

AI 可以幫你把邊界情境「列出來」,但沒辦法幫你決定「這些情境裡哪些是真的可能發生、該怎麼處理」——這個判斷需要對這個系統實際的使用情境有理解,而這正是人該保留的角色。

邊界情境的幾個常見類別

與其每次都從零開始想邊界案例,不如建立一份可以重複拿來對照的分類清單,讓「要求 AI 列邊界情境」這件事變得具體、可執行:

  • 空值/缺值:陣列是空的、物件的某個欄位是 null/undefined、字串是空字串
  • 極端值:數字是 0、負數、超過型別上限、字串超長
  • 型別邊界:浮點數精度問題、日期跨時區/跨夏令時、字串編碼異常
  • 並發/時序:同一個操作被同時觸發兩次、操作順序顛倒
  • 權限/狀態邊界:資源已經被刪除但還在被操作、狀態機裡不該出現的狀態轉換

這份清單不是要求每個函式都要測完全部類別,而是作為一份「動手寫測試前先過一輪」的檢查表——多數邊界情境其實跟這個函式的業務邏輯無關,但至少要主動篩過一次,而不是完全略過。

怎麼把這件事變成一個可以要求的習慣

具體做法很直接:在要求 AI 寫測試之前,先要求它列出邊界情境清單,而且明確告訴它「先別急著寫測試程式碼」。這個中間步驟看似多花了一輪來回,但它把「AI 會不會漏測邊界情境」這個模糊的擔心,變成一個具體、可以逐條審核的清單。

清單列出來之後,人要做的判斷是:哪些情境在這個系統裡真的可能發生(例如訂單商品列表理論上不該是空的,但 API 層有沒有驗證過?)、哪些情境該怎麼處理(拋例外、回傳預設值、還是視為合法輸入)。這個判斷依賴的是對系統實際運作情境的理解,不是測試技巧本身,這正是 AI 沒辦法代勞的部分。

今日思考題

回想你最近一次讓 AI 幫忙寫測試的經驗:那些測試案例裡,有幾個是空值、極端值、或並發情境?如果答案是零,那份測試涵蓋率再高,可能也只是把 happy path 反覆驗證了很多遍。

今日重點回顧

  • AI 生成測試天然偏向 happy path,因為需求描述本身就以正常情況為主,邊界情境很少被明講
  • 建立一份可重複使用的邊界情境分類清單(空值、極端值、型別邊界、並發、權限狀態),比每次臨時想更有效率
  • 具體做法:先要求 AI 列出邊界情境清單、人審過再動手寫測試,而不是直接跳去寫測試程式碼
  • 「這個邊界情境在系統裡會不會真的發生、該怎麼處理」的判斷,是人該保留、AI 沒辦法代勞的部分

明日預告

第二部(Day 8-16)在明天迎來收尾:測試品質的判斷標準——AI 可以幫你寫測試,但誰來判斷這個測試值不值得留下來?


上一篇
Day 14:案例——一個被過度 mock 掉的測試,通過了但沒抓到真正的 bug
系列文
AI 時代的 TDD:讓 AI 寫 Code,但不要讓它決定品質15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言