一句話說明
AI 很擅長寫單元測試和邊界值測試,但整合測試、真實情境的端對端測試、以及安全測試這幾類,AI 生成的內容經常流於表面,需要工程師另外補齊。
AI 輔助開發的測試金字塔
傳統的測試金字塔由下往上分成單元測試、整合測試、端對端測試,數量由多到少。導入 AI 輔助開發之後,這個金字塔的形狀沒有變,但每一層測試的產出方式和可信度出現了明顯差異,這是這篇文章要談的重點。
底層的單元測試,AI 生成的速度快、覆蓋率高,適合大量產出。中層的整合測試,AI 能寫出程式碼但很少能反映真實環境的行為。頂層的端對端測試和安全測試,AI 目前的表現最不可靠,通常需要人工設計測試情境,再讓 AI 協助寫測試程式碼的骨架。
理解這個分佈,才知道在哪裡可以放心讓 AI 全權處理,在哪裡必須自己盯著。
AI 擅長寫的測試
純函式的單元測試。輸入固定,輸出可預期,沒有外部依賴(不連資料庫、不打 API)的函式,AI 幾乎可以直接生成完整的測試案例,包含正常輸入和明顯的邊界值。例如一個計算折扣金額的函式,AI 能很快列出「原價為零」「折扣率超過 100%」「輸入負數」這類案例。
邊界值的窮舉。AI 對「窮舉」這件事特別擅長,給它一個函式的參數型別,它可以快速列出各種邊界組合:空字串、null、undefined、超長字串、特殊字元、極大數字、極小數字。這種需要耐心但不需要太多判斷力的工作,正是 AI 的強項,人類工程師反而容易因為覺得瑣碎而漏掉幾種組合。
資料驅動測試。如果測試邏輯相同、只是輸入資料不同(例如驗證一百組 email 格式是否合法),AI 可以快速產生資料表和對應的測試迴圈,省下大量手動撰寫重複測試的時間。
AI 不擅長寫的測試
整合測試(涉及真實資料庫、真實外部服務)。AI 寫整合測試時,經常會用 mock 取代真實的資料庫連線或 API 呼叫,測試看起來會過,但沒有驗證到真實環境下的行為,例如資料庫的交易鎖定、外部 API 的實際延遲、連線池耗盡等情境。如果 prompt 沒有明確要求「用真實測試資料庫」,AI 傾向用最簡單的方式讓測試通過,也就是大量 mock。
端對端測試中涉及複雜狀態的部分。像是「使用者下單後,庫存扣減、金流狀態更新、通知寄送三件事的順序和一致性」這種跨多個系統的狀態流程,AI 很難在沒有人工提供完整業務脈絡的狀況下設計出有意義的測試案例,它容易只測試單一步驟成功的情況,忽略步驟之間互相影響的部分。
安全測試。AI 對「這支 API 會不會被越權存取」「這個輸入會不會造成注入」這類需要攻擊者思維的測試設計能力有限,除非明確要求並提供攻擊情境範本,否則生成的測試通常只涵蓋功能面是否正常運作,完全不涉及惡意輸入。
生成程式碼後必須額外補上的四類測試
不論 AI 有沒有主動生成測試,以下四類是 AI 產出程式碼之後,工程師應該親自確認有沒有涵蓋的部分。
輸入邊界測試
針對每一個接收外部輸入的函式或 API,確認測試涵蓋 null、空字串、空陣列、超出長度限制的輸入、非預期型別(例如數字欄位傳字串)、特殊字元(引號、換行符、Unicode 表情符號)。這類測試 AI 通常會主動生成一部分,但常常漏掉「超長輸入」和「非預期型別」這兩種,需要人工補齊。
錯誤路徑測試
模擬外部依賴失敗時系統的行為:資料庫連線中斷、第三方 API 逾時或回傳錯誤格式、磁碟空間不足、記憶體不足。這類測試 AI 幾乎不會主動生成,因為它需要模擬「基礎設施層級失敗」而不是「輸入資料有問題」,兩者的測試設計方式不同。可以用 mock 讓依賴的服務拋出例外或延遲回應,確認系統會優雅地降級或重試,而不是整個服務崩潰。
安全測試
驗證授權邏輯的測試,例如使用者 A 是否能存取使用者 B 的資料(IDOR)、未登入的請求是否能存取需要授權的端點、權限較低的角色是否能執行管理員專屬的操作。
注入測試,把常見的注入字串(SQL 注入的 payload、跨站腳本的 payload)當作輸入送進系統,確認系統不會執行這些內容,也不會回傳未經過濾的內容給前端。
這些測試 AI 生成的品質參差不齊,建議工程師自己列出攻擊情境清單,再請 AI 協助把清單轉成可執行的測試程式碼,而不是直接請 AI「幫我寫安全測試」後就照單全收。
併發測試
檢查多個請求同時操作同一份資料時會不會出現競態條件。例如兩個請求同時扣減同一筆庫存,正確的結果應該是庫存不會被扣成負數,但如果程式碼是「先讀取庫存、判斷是否足夠、再寫入新庫存」這種沒有加鎖或使用資料庫層級交易的寫法,兩個同時進來的請求可能都通過判斷,導致庫存被超賣。
AI 生成 CRUD 邏輯時,幾乎不會主動考慮併發情境,因為它是根據單一請求的邏輯流程去生成程式碼,沒有內建「這支程式碼可能同時被多個請求執行」的假設。併發測試通常需要用工具模擬多個請求同時發送(例如用簡單的腳本同時打十次同一支扣庫存的 API),觀察最終結果是否符合預期。
生成測試案例的 prompt 範例
與其請 AI「幫這個函式寫測試」,更有效的做法是把測試類型拆開明確要求,例如:
「請針對這個函式寫測試案例,需要包含以下四類:正常情境(輸入符合預期格式的資料)、邊界情境(空輸入、null、超過長度限制的輸入)、錯誤情境(型別不符、缺少必要欄位)、安全情境(嘗試 SQL 注入字串、嘗試超長輸入造成緩衝區問題)。每個測試案例請說明預期的行為是什麼。」
這種拆分式的 prompt 能明顯提高 AI 產出測試案例的完整度,因為它把原本 AI 容易忽略的類別(尤其是安全情境)明確點出來,逼它針對這幾個方向思考,而不是只寫最直覺的正常情境測試。
另一個實用的做法是先請 AI 條列測試案例的清單(不寫程式碼),人工檢查清單有沒有漏掉重要情境,確認清單完整之後再請 AI 把清單轉成實際的測試程式碼。這樣可以在寫程式碼之前先抓到設計上的疏漏,比事後看測試程式碼再抓漏更有效率。
工具比較
GitHub Copilot 的測試生成功能整合在編輯器裡,適合針對單一函式快速產生測試骨架,反應速度快,但通常只根據函式簽名和少量上下文生成,對於需要理解整個系統行為的測試(例如跨模組的整合測試)表現有限,比較適合用在單元測試這一層。
Claude Code 在處理較大範圍的測試撰寫時表現不錯,因為它能讀取整個專案的結構和相關檔案,寫測試時比較容易考慮到專案既有的測試風格和 mock 慣例。缺點跟其他工具一樣,如果沒有明確要求涵蓋安全與邊界情境,預設生成的內容仍然偏向正常路徑。
Cursor 的測試功能介於前兩者之間,在編輯器內對單一檔案的測試生成體驗流暢,若要涵蓋跨檔案的整合測試,同樣需要人工提供更多上下文才能得到有用的結果。
整體來說,這幾個工具在「根據明確指示生成測試」這件事上都做得不錯,差異主要在於能不能自動理解「應該測什麼」,這部分目前都還需要人工把關。
什麼時候不該讓 AI 寫測試
如果程式碼是 AI 生成的,測試也讓同一個或類似的 AI 工具生成,等於用同一套邏輯假設去驗證自己,這是一種循環驗證,很容易發生「AI 沒想到的邊界情況,測試也同樣沒想到」。例如 AI 寫的 API 忘記檢查資料擁有權,AI 寫的測試也很可能只測試「有登入就能存取」,不會主動測試「登入的是不是正確的擁有者」,因為兩者出自類似的思考盲點。
這種情況下,比較安全的做法是測試的「情境設計」由人來做,AI 負責把設計好的情境轉成可執行的程式碼。尤其是安全相關的測試,攻擊情境的發想應該來自對系統威脅模型的理解,而不是讓生成程式碼的同一套邏輯自己出題自己作答。
另外,對於商業邏輯高度複雜、涉及金錢計算或法規遵循的模組(例如利息計算、稅務邏輯),這類測試案例的正確性要求極高,建議由熟悉業務規則的人親自設計測試案例,AI 頂多協助處理程式碼撰寫的部分,不建議讓它決定「這個計算結果應該是多少」。
安全考量與限制
測試涵蓋率的數字不能直接當作安全指標。一個專案就算單元測試覆蓋率達到 90%,如果這些測試全部只測正常路徑,涵蓋率再高也測不出授權漏洞或注入風險,涵蓋率是程式碼有沒有被執行到的指標,不是測試有沒有測到正確情境的指標。
測試本身也可能藏有問題。如果 AI 生成的測試裡 mock 掉了關鍵的驗證邏輯(例如把授權檢查的函式直接 mock 成永遠回傳成功),測試會一直過,但完全沒有驗證到真實的授權邏輯是否正確。審查測試程式碼時,需要特別留意 mock 的範圍有沒有不小心蓋掉了應該被測試的邏輯本身。
安全測試無法取代滲透測試或紅隊演練。自動化的安全測試案例能抓到已知模式的漏洞(常見的注入 payload、簡單的越權存取),但沒辦法取代有經驗的人手動探索系統,尋找當初設計測試案例時完全沒設想到的攻擊路徑。對外部曝露、處理敏感資料的系統,建議在自動化測試之外,定期安排人工的滲透測試。
最後,測試策略需要隨著系統風險等級調整投入程度。內部工具和對外的金融交易系統,該花在安全測試和併發測試上的力氣應該完全不同,不需要對所有專案套用同一套嚴格程度的清單,但至少授權相關的測試,任何有使用者資料的系統都不建議省略。
知識檢測
讀完文章後,測試一下你對這個主題的理解。
常見問題
AI 生成的測試案例已經很多,是不是就代表測試做得夠完整?
不一定,數量多不等於涵蓋面廣。如果大部分測試案例都集中在正常路徑,就算有上百個測試案例,安全性和邊界情況仍然可能沒有涵蓋到。判斷測試夠不夠完整,要看類型的分佈,而不是只看數量。
併發測試很難寫,有沒有比較簡單的做法?
最簡單的方式是寫一個腳本同時發送多個相同的請求(例如用 Promise.all 同時打十次扣庫存的 API),觀察最終結果有沒有出現超賣或資料不一致。不需要一開始就用複雜的壓力測試工具,先用簡單的方式驗證核心邏輯有沒有基本的併發保護即可。
小型專案或內部工具是否可以省略安全測試?
可以依風險調整測試的嚴謹程度,但只要系統會處理使用者資料或需要登入,授權相關的測試(誰能存取誰的資料)建議至少要有基本涵蓋,這類漏洞後續造成的影響往往比想像中大,補測試的成本又相對低。
AI 寫的測試通過了,為什麼上線後還是出問題?
常見原因是測試涵蓋的情境跟正式環境的實際使用情況有落差,例如測試用的資料量遠小於正式環境、測試沒有模擬真實的併發流量、測試的 mock 跟真實外部服務的行為不完全一致。這也是為什麼整合測試和正式環境前的壓力測試不能被單元測試完全取代。
要花多少比例的時間在補測試上?
沒有固定比例,比較實際的做法是先確認前面提到的四類(輸入邊界、錯誤路徑、安全、併發)是否至少有基本涵蓋,再依照專案風險程度決定要投入多少。對外部使用者開放、涉及金錢或個資的系統,這部分的時間投入不建議壓縮。
相關文章
參考資料
- OWASP Testing Guide — OWASP 網頁應用程式安全測試指南
- Google Testing Blog: Test Sizes — 關於單元、整合、端對端測試分層的經典討論