iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
Vibe Coding

從 GAS 到 Cloudflare D1:AI Agent 如何打造、接手並重構真實便當系統系列 第 14 篇

Day 14|測試不是最後補上去的,而是系統的「業務記憶」

  • 分享至 

  • xImage
  •  

Bento Day 14

Day 12 把需求寫成可判定 PASS / FAIL 的驗收條件(Acceptance Criteria,AC),Day 13 再把一條使用者旅程(User Journey)拆成責任與觀察點。

接著還有一個問題:

今天人工驗過的規則,下次 AI 再改別的功能時,誰還記得?

如果答案是「到時候再重測一次」,那這些規則仍然主要存在人的腦袋裡。

值得留下來的測試,是把已確認的業務規則(Business Rule)保存成未來仍可重跑的回歸契約(Regression Contract)。

這對 Vibe Coding 特別重要。AI 讓修改變快,也讓一次碰很多檔案、很多流程變得容易;系統若沒有同樣可重跑的記憶,舊規則就更容易在下一次修改時被忘掉。

一個功能做完,不代表它已經被系統記住

代點餐(delegated ordering)很適合拿來看這件事。

前兩天已經確認幾條規則:

  • 一般 User 不能自行偽造 targetUserId 替別人下單;
  • Admin / ProxyAdmin 有不同的 delegated authority;
  • 被代點的人(target)必須是可操作的有效成員;
  • 唯讀查看(View As)仍然只有唯讀語意;
  • 訂單、扣款與退款仍屬於被代點的 target。

Day 14 不再重講身份邊界,而是問:

這些規則下一次被碰到時,會不會自己跳出來提醒我們?

真實 repo 的 orders-delegated.test.js 留下了幾個直接對應業務規則的 case:

  • User 偽造 targetUserId 時回傳 403,而且 target 名下不會新增訂單;
  • inactive、historical provisional、profile 不完整的 target 會被拒絕;
  • target discovery 只回傳符合資格的成員;
  • 沒綁 LINE、但已是有效 canonical member 的使用者仍可被代點;
  • 建立與取消 delegated order 後,target balance 正確,實際操作的人(actor)balance 不被改動。

這些 case 不是為了把測試數量堆高。

它們記住的是:

可以替別人操作
≠
取得對方資料的 ownership

回歸測試(Regression)最有價值的地方,是它也記得「不能發生什麼」

只測成功路徑(happy path)很容易得到:

Admin 選一個人
→ 建立訂單成功
→ API 回 200

這只能證明功能能跑。

repo 裡另有一條 regression 專門驗:

Given 一般 User
When request 偷帶 targetUserId
Then 403 DELEGATED_ORDER_FORBIDDEN
And target 名下訂單數仍是 0

這裡同時驗了「被拒絕」和「拒絕後沒有副作用」。

如果只看 status code,未來某次 refactor 仍可能發生:

資料先寫入
→ 後面才判定失敗
→ 畫面顯示錯誤
→ DB 卻已被改動

所以重要規則不能只驗回應訊息,還要驗不該留下的狀態真的沒有留下。

驗收條件(Acceptance Criteria)和回歸契約(Regression Contract)應該能互相找到

Day 12 的 AC 描述「什麼叫做做對」。

Day 14 再問下一題:

這個 Test 到底替哪條 Business Rule 看門?

例如:

AC
一般 User 不得替其他人建立 delegated order

Regression Contract
- forged targetUserId → 403
- target order count 不增加

餘額規則也是同樣邏輯:create / cancel 都作用在 target,actor balance 必須保持不變。

如果一個 Test 說不出自己保護哪條 Business Rule,它很可能只是在固定當下的實作細節。

Bento Day 14 regression business memory

真實踩坑會決定哪些 Test 值得留下

AI 很會生成測試。

輸入 Component、function 或 endpoint,很快就能補出一批 case;但生成成本降低,也代表無意義測試同樣變便宜。

便當系統有一個很具體的 UI regression。

delegated order 成功後,Worker 已回傳最新的 newBalance。畫面可以立刻更新被代點成員的餘額,但管理頁另外還有一份 member balance cache。

如果只更新眼前畫面,餘額管理列表仍可能保留舊值。

delegated-order-ui.test.cjs 把這次踩坑留下來:

member balance cache = 0
delegated response.newBalance = -100
↓
delegated banner 立即顯示 -100
↓
member balance cache 標記失效
↓
再次進入餘額管理
↓
重新向 API 讀取
↓
列表顯示 -100

這個 Test 保護的不是某一行 React state code。

它保護的是一條資料規則:

當前畫面可以使用 mutation 回傳的新值立即更新;其他舊快取不能假裝自己仍是最新資料,必須失效後重新讀取。

這就比「某個 setter 有沒有被呼叫」更值得成為長期 regression。

Test 要保護規則,不要過度固定實作

面對 AI 一次生成很多測試,我會再問第二題:

如果實作換掉,這個 Test 還有沒有意義?

未來即使:

  • React state 重整;
  • handler 改名;
  • API client 被抽換;
  • domain function 被拆分;

只要 Business Rule 沒變,重要的 regression 應該還能表達同一個契約。

實務上不可能全部都是黑箱測試。某些前端 wiring 仍會需要 source-level regression。

但就算是 source-level test,也應該先知道它保護的行為是什麼,而不是把目前程式碼長相本身當成需求。

已知基準線(Known Baseline):先知道原本就壞什麼

還有一種記憶不是業務規則,而是「修改前的系統狀態」。

如果 Repository 原本就有已知 failure,AI 改完看到紅字時,不能直接判定是這次改壞;反過來,也不能把所有新紅字都丟進「本來就壞」這個桶子。

最少要能比較:

Before
- 哪些檢查原本 PASS
- 哪些 failure 原本就存在

After
- 是否多出新的 failure
- 原本 failure 是否維持同一型態

這讓 Regression 不只保存規則,也保留「這次修改前的基準線」。

不是每個問題都要永久變成 Test

Regression 會有成本:

  • suite 執行時間增加;
  • fixture 變複雜;
  • requirement 改變時要維護;
  • 過度綁定 implementation 的 test 會阻礙正常 refactor。

所以判斷標準不是「發生過就全部寫進測試」。

比較值得留下來的,通常是:

  • 未來很可能再次被碰到;
  • 壞掉時不容易第一眼發現;
  • 會影響資料、權限、餘額或使用者狀態;
  • 能穩定重現並形成明確 PASS / FAIL。

偶發、無法重現,或只屬於一次性資料修復的事件,不一定值得永久加入 suite。

Day 14 留下的是「把學費存進系統」

Vibe Coding 大幅降低修改成本,但這也讓「每次改完要留下什麼」更重要。

這篇可以帶走的流程很短:

Incident / Requirement
↓
Acceptance Criteria
↓
找出容易再次被破壞的 Business Rule
↓
寫成 Regression Contract
↓
驗結果 + side effect + data ownership
↓
未來修改時重跑

Patch 解決這一次。

Regression 讓下一次不用再付同一筆學費。

下一篇會處理另一個問題:當 Test、UI 或 Production 現象真的告訴你「有問題」,要怎麼用 Evidence 縮小 fault domain,而不是從整個 Repository 開始猜。

本系列實作專案

這是一套持續開發中的便當訂購系統。文章著重「為什麼」,GitHub 保留實際程式碼、測試與演進紀錄。

這篇主要核對:

  • worker-poc/tests/orders-delegated.test.js:delegated authority、target eligibility、target-owned order / balance 與 forbidden side effect;
  • tests/delegated-order-ui.test.cjs:authoritative newBalance、member-balance cache invalidation 與再次讀取;
  • CHANGELOG.md:v0.14.0 delegated ordering 與 v0.14.1 balance refresh follow-up。

GitHub:https://github.com/henryfir456/bento-order-app


上一篇
Day 13|一個需求跨五層時,我怎麼知道每一層各自負責什麼?
下一篇
Day 15|Debug 最有價值的不是猜,而是把證據串起來
系列文
從 GAS 到 Cloudflare D1:AI Agent 如何打造、接手並重構真實便當系統 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言