測試驅動開發
TDD 就是紅 → 綠循環。這個技能是讓此循環產出值得保留之測試的參考:包含什麼是好的測試、測試應該放在哪裡、反模式,以及循環的規則。每個章節在每次循環中都適用:在循環進行之前與期間查閱它們,而不是之後。
在探索程式碼庫時,請閱讀 GLOSSARY.md(如果存在),以便測試名稱和介面詞彙與專案的領域語言匹配,並尊重您正在觸及的區域中的 ADR。
什麼是好的測試
測試透過公開介面驗證行為,而非實作細節。程式碼可以完全改變;測試不應該。一個好的測試讀起來就像一份規格說明:「使用者可以使用有效的購物車結帳」確切告訴您存在的功能,並且由於它不關心內部結構,因此能在重構後依然存活。
範例請參閱 tests.md,模擬指引請參閱 mocking.md。
縫隙:測試放置的位置
縫隙是您進行測試的公開邊界:您觀察行為而無需觸及內部的介面。測試位於縫隙處,而不是針對內部。
僅在預先約定的縫隙處進行測試。 在編寫任何測試之前,寫下要測試的縫隙並與使用者確認。沒有測試寫在未經確認的縫隙上。您無法測試所有東西,因此事先約定好縫隙,才能將測試精力集中在關鍵路徑和複雜邏輯上,而不是每個邊緣情況。
提問:「公開介面是什麼?我們應該測試哪些縫隙?」為每個提議的縫隙寫一行備註,說明它能捕捉到什麼、遺漏了什麼。
當該介面的形狀本身存疑時(模組的深度、縫隙應歸屬何處、介面應該暴露什麼),請使用「codebase-design」參數呼叫技能工具。這是關於模組、介面、深度、縫隙、轉接器、槓桿和局部性等詞彙的共同來源,是供諮詢的參考,而非需要執行的會話。
反模式
- 與實作耦合:模擬內部協作者、測試私有方法,或透過側通道驗證(查詢資料庫而不是使用介面)。跡象:重構時測試失敗,但行為並未改變。
- 同義反覆:斷言用與程式碼相同的方式重新計算預期值(
expect(add(a, b)).toBe(a + b),以相同方式手動衍生的快照,斷言等於自身的常數),因此它必然通過,永遠無法與程式碼產生分歧。預期值必須來自獨立的真相來源:已知良好的字面值、經過計算的範例、規格書。 - 水平切片:先編寫所有測試,然後才是所有實作。大量測試驗證的是想像中的行為:您測試的是事物的形狀而非使用者可見的行為,測試對實際變化不敏感,並且在理解實作之前就承諾了測試結構。應改為以垂直切片的方式進行:一個測試 → 一個實作 → 重複,每個測試都是一顆追蹤子彈,回應上一個循環教會您的內容。
循環的規則
- 紅燈先於綠燈。 先編寫會失敗的測試,然後只編寫足以通過它的程式碼。不要預測未來的測試或添加推測性的功能。
- 一次一個切片。 每次循環只處理一個縫隙、一個測試、一個最小的實作。
- 重構不屬於循環的一部分。 它屬於審查階段(請參閱
code-review技能),而不是紅 → 綠的實作循環。