iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0

前言

驗收條件有很多種寫法,但因為 AI 產出的速度遠快過人 review 的速度,因此只有能自動驗證的那一部分,才有可能跟上 AI 的產出速度。


昨天說到

昨天把工作單元切好了。

在真正開始開發之前,我想先處理一件事:規格裡寫了幾十條「系統應該怎樣」,其中有多少是真的可以被機器驗證的?

如果最後還是得靠人一條一條看,AI 產得再快,review 都會變成瓶頸。


驗收條件有兩種,只有一種能自動驗證

誰來驗 被違反的時候
描述性驗收條件 沒有任何事發生
可執行的檢查 機器 報錯

/speckit-specify 會順手產一份規格品質清單,拿它當例子:

- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Edge cases are identified

這份清單當然有它的價值,它檢查的是規格本身的品質。

真正重要的是分清楚:哪些需要人判斷,哪些可以交給機器驗證。


為什麼測試對 AI 協作特別重要

一、瓶頸在核可,不在產出

AI 可以一次產出大量規格、程式碼和測試,但 review 的速度不會因此等比例增加,人還是得一行一行讀、一個情境一個情境確認。

所以在整條流程裡,能自動驗證的部分,是唯一不需要增加人工 review 成本的驗收方式。

二、先寫測試 = 在交出去之前就把「完成」定死

如果只把規格交給 AI,「做完了沒」最後還是由 AI 自己判斷,它會用自己的理解補完沒有寫清楚的地方,然後直接告訴你完成了。

但如果先把規格轉成測試,「完成」的判定就不再只存在 AI 的回答裡。

測試通過,就是目前定義下的完成,測試沒通過,就是還沒完成,讓完成的判準變成可執行的東西。

三、AI 一次產出整包,紅燈不會自己出現

這是我實際跑過一輪後最有感的地方,把規格交給 AI,拿回來的通常不是他執行的過程:

寫測試
↓
測試失敗
↓
寫實作
↓
測試通過

而是執行完的結果:models / services / api / tests 一次全出來。

這會讓傳統 TDD 裡很重要的「紅燈階段」消失,因為 AI 很可能是對著自己剛寫完的實作,再寫出一套測試。

結果就是:測試全綠,但沒有人證明過它真的能抓到錯誤。

所以現在我會要求:先看到紅燈,再相信綠燈,紅燈至少證明了這條測試真的有能力因為某個規則被違反而失敗。


測試就是可執行的規格

這個專案裡,有三種規則適合直接轉成測試。

一、「沒有這條路」

例如:已送出的版本不可修改。

其中一種最直接的保護方式,就是根本沒有修改版本的 API,所以測試可以直接檢查路由:

assert version_routes == {
    "/api/versions/{version_id}": ["GET"],
    "/api/versions/{version_id}/confirm": ["POST"],
    "/api/versions/{version_id}/reject": ["POST"],
}

如果之後有人,或某個 AI session,偷偷加了一支 PATCH,測試會直接紅。

文件裡寫:請不要新增修改版本的 endpoint,不會擋住任何人。

二、「這個東西必須存在」

資料庫裡有兩支 trigger 在守唯讀規則,問題是 alembic autogenerate 不會替我產生 trigger,也不會告訴我 trigger 不見了,所以不能只測「現在資料不能被修改」,要直接查資料庫系統表,確認這兩支 trigger 還存在。

因為 migration 有可能成功執行,但真正重要的東西根本沒有被建立。

三、「兩件事同時發生」

還有一種規則,文件很容易寫,但很難只靠一般單元測試表達,例如:最後一個人確認的同時,另一個人退回。兩個請求如果同時讀到「待確認」,各自往下執行,就可能產生競態條件。

要驗證這件事,得真的讓兩個操作同時發生,再確認最後的狀態符不符合規則。這種情境文件描述得出來,但只有測試能反覆驗證它沒有真的發生。


規則要寫成看得見的形式

所以從這個工作單元開始,我也把開發流程寫進 CLAUDE.md:

每個工作單元走 RED → GREEN → IMPROVE,至少兩筆 commit:
`test:` 在前(測試紅),`feat:` 在後(測試綠)。

這裡我特別要求兩筆 commit,它讓:「有沒有先寫測試?」這個問題,從一個需要相信開發者的問題,變成可以從 git log 查到的紀錄。這跟前面幾天得到的結論其實是一樣的:

規則不能只寫成「請遵守」,還要寫成之後可以檢查的形式。


真的跑一輪

拿「確認與退回」這個工作單元實際跑一輪,我先把四條驗收條件轉成測試,一共六個測試案例,第一次執行全部紅燈,是因為功能還沒完成。

接著開始實作,測試一條一條變綠,中間也發現一個 UI 結構問題:確認進度原本只是散落在一段文字裡,測試很難準確驗證。把它拆成獨立元素後,不只測試比較容易寫,UI 結構也更清楚。

最後在 IMPROVE 階段,又發現一個原本驗收條件沒有涵蓋的問題:作者看得到「正在等待確認」,但真正需要做決定的確認人,打開畫面後卻什麼都看不到。

這個 Bug 很值得記下來,即使測試全綠,不代表系統沒有問題,只能確定目前定義出來的驗收條件都通過了。測試的價值不只是「抓 Bug」,更重要的是,在實作之前先規範出到底什麼叫做完成?


結論

實際跑完第一個工作單元後,我留下三個原則。

1. 紅燈不是形式,是驗證測試有效

如果測試從來沒有失敗過,我其實不知道它能不能抓到問題。所以先紅,再綠,不是為了遵守 TDD 的儀式,而是先確認測試真的有能力驗證這條規則。

2. 測試是驗收條件的可執行版本

規格裡寫:不在確認名單的人不能確認,測試則把它變成:如果真的出現這個情境,測試必須失敗。

這兩者最大的差別是:前者需要有人記得;後者會自己出聲。

3. 綠燈不是終點

開發流程變成:

規格
↓
找出可以自動驗證的規則
↓
先寫測試
↓
RED
↓
AI 實作
↓
GREEN
↓
IMPROVE
↓
人工確認「有沒有漏掉沒被測試描述的事情」

測試負責守住已經定義出來的規則,而人工 review,則負責繼續找:

是不是還有我們根本沒想到的規則?

明天:後端骨架,一條 API 走完分層。


上一篇
Day 17|Plan 不是第二份 Spec:從規格到工作單元
系列文
30 天打造我的 AI 開發工作流:從需求分析到上線18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言