用測試和行為描述約束 AI 寫程式,少堆史山

整理用 TDD 和 BDD 約束 AI 寫程式的基本思路:先把需求寫成可確認的行為描述,再轉換成測試,最後讓 AI 按測試實作功能。

用 AI 寫程式時,最容易出現的體驗是:前期很快,後期很亂。功能剛開始能迅速搭起來,但專案一大、修改次數一多,就會出現一個 bug 改完又冒出三個 bug 的情況。

這不完全是 AI 的問題。很多人寫程式也會這樣,只是 AI 寫得更快,問題暴露得也更快。要減少這種失控,關鍵不是讓 AI「更努力」,而是給它更清楚的邊界:先說明什麼結果算對,再讓它寫實作。

TDD 和 BDD 就適合放到 AI 程式設計流程裡。TDD 負責把「對不對」變成自動測試,BDD 負責把「是不是我要的功能」變成人能看懂的行為描述。兩者結合,可以讓 AI 少猜、少自由發揮,也更容易被檢查。

TDD 解決什麼問題

TDD 是 Test Driven Development,也就是測試驅動開發。它的基本順序是:

  1. 先寫測試。
  2. 執行測試,確認它現在失敗。
  3. 再寫功能程式碼。
  4. 持續修改實作,直到測試通過。

這和很多人習慣的做法相反。平時寫一個排序函式,直覺上會先寫函式,再隨便輸入幾個數字看看結果對不對。TDD 則要求先把預期寫成測試,例如輸入 [3, 1, 2] 時應該得到 [1, 2, 3],輸入空陣列時應該回傳空陣列,輸入包含重複數字時結果也應該正確。

這樣做的意義是:開發開始前,正確結果已經被定義清楚了。後面無論誰改程式碼,只要重新跑測試,就能知道有沒有破壞之前約定好的行為。

為什麼 TDD 以前不容易堅持

TDD 聽起來很美,但在真實專案裡並不容易長期執行。

一是它反直覺。面對一個空檔案時,很多人更想先把功能寫出來,而不是先寫測試。尤其需求還不清楚時,測試案例也很難落筆。

二是需求變化快。今天認真寫下的十幾個測試,明天需求一改,可能就要大面積重寫。短期看,它會讓開發節奏變慢。

三是測試本身也需要成本。測試程式碼不是憑空出現的,過去它需要工程師自己寫、自己維護、自己解釋價值。對只看短期交付速度的團隊來說,這件事很容易被壓掉。

但 AI 改變了這個成本結構。把需求轉成測試程式碼,恰好是 AI 很擅長的工作。讓 AI 根據測試去補實作,也比讓它對著一段模糊描述自由發揮可靠得多。

AI 寫程式時怎麼用 TDD

使用 AI 寫功能時,可以把提示方式從「幫我實作這個功能」改成下面這個順序:

  1. 讓 AI 先根據需求列出測試案例。
  2. 要求每個測試案例都有中文說明。
  3. 先 review 測試案例是否符合真實需求。
  4. 確認測試後,再讓 AI 寫功能實作。
  5. 要求 AI 執行測試,並根據失敗結果繼續修正。

這時,人主要 review 的不是一大段實作程式碼,而是測試是否說清楚了需求。測試案例通常更接近「輸入是什麼、輸出應該是什麼、邊界情況怎麼處理」,比直接讀實作邏輯輕鬆很多。

例如可以這樣要求 AI:

1
2
3
先不要實作功能。
請根據下面的需求編寫測試案例,每個測試案例用中文註解說明覆蓋的業務規則。
測試確認後,再根據測試實作程式碼。

這個流程能減少兩類常見問題:一類是 AI 寫著寫著偏題,另一類是後續修改時把舊功能改壞。

TDD 還不夠

只有 TDD 仍然有兩個缺口。

第一個缺口是:測試都通過,不等於產品真的符合預期。測試只能證明程式碼滿足了測試裡寫下的規則。如果測試本身沒有表達清楚使用者需求,程式碼仍然可能「正確地做錯事」。

第二個缺口是:測試程式碼對非技術使用者仍然不友好。哪怕有中文註解,很多人還是不願意閱讀一堆單元測試。需求越偏產品體驗,越難直接從測試程式碼裡確認「這是不是我要的東西」。

這時就需要 BDD。

BDD 解決什麼問題

BDD 是 Behavior Driven Development,也就是行為驅動開發。它關注的不是程式碼內部怎麼寫,而是系統在某個場景下應該表現出什麼行為。

BDD 常用的描述方式是 Given / When / Then:

  • Given:給定某個前置狀態。
  • When:當使用者或系統執行某個動作。
  • Then:應該得到某個結果。

例如一個帶吸血效果的遊戲角色,可以這樣描述:

1
2
3
4
5
Given 棋盤上有一個剩餘 1 點生命、攻擊力為 2、最大生命為 5 的吸血鬼
And 相鄰格子有一個剩餘 10 點生命的敵方單位
When 吸血鬼攻擊這個敵方單位
Then 敵方單位剩餘 8 點生命
And 吸血鬼恢復到 3 點生命

這段話不是程式碼,但它比「攻擊敵人時恢復生命」精確得多。它說明了初始狀態、動作和結果,也暴露出後續需要補充的問題:如果敵人只剩 1 點血,吸血鬼按造成傷害恢復,還是按攻擊力恢復?如果吸血鬼已經滿血,溢出的治療怎麼處理?

這些問題越早被問出來,AI 後面越不容易亂猜。

為什麼 BDD 很適合 AI

BDD 過去推行成本也不低。它要求產品、開發、測試用同一套行為描述溝通,而現實裡很多團隊並沒有這種協作習慣。

但 AI 時代,BDD 的成本下降了。你只需要先寫一句粗略需求,例如:

1
吸血鬼攻擊敵人後,恢復與造成傷害等量的生命值。

然後讓 AI 生成 Given / When / Then 場景。做得好的 AI 會主動補充邊界情況,並追問不明確的規則。你需要做的是確認這些行為描述,而不是直接讀實作程式碼。

一旦行為描述確認清楚,再讓 AI 把它轉換成測試程式碼,最後根據測試實作功能,路徑就順了很多。

一套更穩的 AI 程式設計流程

實際使用時,可以把 BDD 和 TDD 串起來:

  1. 先用自然語言寫需求。
  2. 讓 AI 轉成 BDD 行為場景。
  3. 人確認 Given / When / Then 是否符合預期。
  4. 讓 AI 把行為場景轉換成自動測試。
  5. 人快速 review 測試覆蓋範圍。
  6. 讓 AI 實作功能。
  7. 執行測試,失敗就讓 AI 根據錯誤繼續修正。
  8. 最後再做一次人工驗收和程式碼 review。

這裡的關鍵是順序。不要一開始就讓 AI 寫完整實作,而是先讓它把需求變成可確認的行為,再變成可執行的測試。這樣 AI 的自由發揮空間會小很多。

可以直接使用類似這樣的提示詞:

1
2
3
4
5
6
7
請按 BDD + TDD 的流程處理這個需求。

第一步:先把需求整理成 Given / When / Then 行為場景,不要寫程式碼。
第二步:列出你發現的不明確規則,並向我確認。
第三步:在行為場景確認後,再把它們轉換成測試案例。
第四步:測試確認後,再實作功能。
第五步:執行測試,根據失敗結果修復,直到測試通過。

這類提示詞不複雜,但能明顯改變 AI 的工作方式。它會先收斂需求,再進入實作,而不是一上來就寫一堆看似完整、實際難以驗證的程式碼。

適合優先使用的場景

BDD + TDD 不一定適合所有任務。對於一次性腳本、臨時資料處理、小範圍樣式調整,完整流程可能太重。

它更適合這些場景:

  • 業務規則多,容易理解錯。
  • 邊界條件多,後續還會持續修改。
  • 遊戲、計費、權限、狀態機、表單驗證等邏輯密集功能。
  • 需要多人協作確認需求。
  • 程式碼將長期維護,不只是一次性生成。
  • 已經出現「AI 越改越亂」的專案。

如果只是讓 AI 改一個按鈕文案,不必上完整流程。但如果要做一套角色技能系統、訂單狀態流轉、權限判斷、積分規則,先寫行為場景和測試會更划算。

使用時注意什麼

第一,測試不是越多越好。測試應該覆蓋關鍵規則和高風險邊界,而不是把實作細節全部鎖死。否則需求稍微變化,測試就會變成維護負擔。

第二,BDD 場景要寫具體。不要寫「系統應該正常工作」「體驗應該流暢」這類無法驗證的描述。要寫清楚給定什麼狀態、發生什麼動作、結果應該是什麼。

第三,人仍然要 review。AI 可以生成測試和行為場景,但它不知道你真正想要的產品取捨。尤其是邊界規則,必須由人確認。

第四,測試通過後還要實際執行功能。自動測試能兜住邏輯問題,但介面體驗、效能、互動細節、使用者感受仍然需要人工驗收。

小結

AI 寫程式快,但快不等於穩。越是複雜需求,越不能只靠一句「幫我實作」。更好的方式是先把需求拆成可確認的行為,再把行為變成可執行的測試,最後讓 AI 按測試實作程式碼。

TDD 讓 AI 知道什麼結果算對,BDD 讓人更容易確認這是不是自己想要的功能。兩者合起來,不是為了增加儀式感,而是為了減少 AI 的猜測空間,把「寫得快」變成「改得穩」。

记录并分享
使用 Hugo 建立
主題 StackJimmy 設計