Claude Code TDD 工作流完整教學 — 讓 AI 先寫測試再寫程式的正確姿勢
你去餐廳點餐的時候,不會先讓廚師煮完再告訴他你要什麼。你會先點菜——「我要一份牛排,七分熟,不要蘑菇醬」——然後廚師根據你的規格去做。
寫程式也是一樣。測試就是你的點單。程式碼就是廚師做出來的菜。
大部分人用 Claude Code 的時候,順序是反的:先叫 AI 寫程式碼,然後自己補測試,發現問題再改。這就像讓廚師先做一道他覺得你應該會喜歡的菜,然後你看了之後說「我其實不吃蘑菇」。浪費時間,浪費食材。
TDD(Test-Driven Development)把順序翻過來:先寫測試,再寫程式碼,最後重構。跟 Claude Code 搭配的時候,這個順序的效果特別好——因為測試就是最精確的需求規格。你用測試告訴 AI「我要的結果長這樣」,AI 就不用猜了。
Red-Green-Refactor:三步循環
TDD 的核心只有三步,用顏色記最快:
Red — 寫一個會失敗的測試。這個測試描述你要的行為,但對應的程式碼還不存在,所以它一定會失敗。跑一下確認是紅的。
Green — 寫最少的程式碼讓測試通過。不要多寫,不要考慮架構,不要想「順便加個 feature」。目標就是從紅變綠,其他都不管。
Refactor — 測試綠了之後,回頭看程式碼有沒有重複、命名有沒有清楚、結構有沒有合理。改的時候隨時跑測試,確保還是綠的。
然後回到 Red,寫下一個測試。循環。
這個循環的妙處在於:你永遠知道目前的程式碼是對的。每一步都有測試保護。出問題的時候,只可能是你剛剛改的那幾行。debug 範圍從「整個專案」縮小到「最後三分鐘寫的東西」。
跟 Claude Code 搭配的實際做法
打開 Claude Code,第一句話不是「幫我寫一個 XXX 功能」。是這樣:
1 | 幫我寫一個測試,驗證 calculateDiscount 函式的行為: |
Claude Code 會產出一組測試。你跑一下,確認全部失敗(Red)。然後:
1 | 現在寫 calculateDiscount 的實作,讓所有測試通過。用最簡單的方式,不要過度設計。 |
Claude Code 寫完實作,你跑測試,全部綠了(Green)。最後:
1 | 測試都通過了。看一下實作有沒有可以改善的地方——命名、結構、重複的部分。改完要確保測試還是全部通過。 |
三步完成。整個過程你在做的事只有一件:定義規格。寫程式碼和重構都交給 AI,但你始終透過測試掌握「對不對」的判斷權。
為什麼「先測試」對 AI 特別有效
Claude Code 跟人類工程師有一個根本性的差異:它不會覺得寫測試很無聊。
人類工程師做 TDD 的最大障礙是心理的——寫完功能程式碼之後,回頭寫測試感覺像在做重複的事。但如果測試是先寫的,功能程式碼反而變成「把紅的變綠的」的通關遊戲,反而有動力。
但對 AI 來說,更根本的好處是:測試消除了需求的模糊性。
你跟 Claude Code 說「寫一個折扣計算功能」,它要猜你的業務規則。打幾折?什麼條件?例外情況怎麼處理?AI 必須做很多假設,而每個假設都可能是錯的。
但如果你先寫好測試——assert calculate_discount(1500, is_vip=False) == 1350——AI 不需要猜任何東西。規格就在測試裡,精確到數字。
結果是:AI 產出的程式碼第一次就對的機率大幅提升,你花在「看 AI 寫的東西對不對」上面的時間大幅下降。
好,講完理論了。接下來是實戰。
實戰範例:用 TDD 做一個 URL 短縮服務
不是完整專案,只抓最核心的邏輯來示範流程。
Step 1:寫測試(Red)
1 | 我要做一個 URL shortener 的核心邏輯。先幫我寫測試,框架用 pytest: |
Claude Code 會產出大概這樣的東西:
1 | def test_shorten_returns_six_char_code(): |
跑一下:全部紅的。完美。
Step 2:寫實作(Green)
1 | 測試寫好了,全部失敗。現在寫 shorten 和 resolve 的實作,讓測試通過。用最簡單的方式。 |
Claude Code 會用 hashlib 或隨機生成的方式實作。跑測試——全部綠了。
Step 3:重構(Refactor)
1 | 測試通過了。看一下有沒有可以改善的地方: |
這一步通常會讓 Claude Code 把 storage 抽成一個 protocol/interface,方便之後換成 Redis 或資料庫。改完跑測試,還是全綠。
三步走完,你有了一個有測試保護、結構清楚的核心模組。整個過程大概十分鐘。
五個常見的坑
1. AI 寫的測試太寬鬆。 Claude Code 有時候會寫出 assert result is not None 這種什麼都能過的測試。看到這種要立刻改掉——測試的價值在於精確。assert len(code) == 6 比 assert code 有意義得多。
2. 跳過 Red 階段。 有人會叫 AI 同時寫測試和實作。不要這樣做。如果你從來沒看到測試失敗過,你不知道測試是不是真的在檢查你以為它在檢查的東西。一個從來沒紅過的測試,跟沒有測試一樣。
3. Green 階段寫太多。 叫 AI「讓測試通過」的時候,它有時會順便加你沒要求的功能。加了就加了?不行。額外的功能沒有對應的測試保護,等於是盲區。要嘛補測試,要嘛刪掉。
4. Refactor 階段改測試。 重構的對象是程式碼,不是測試。如果你在重構的時候改了測試讓它通過,那不叫重構,叫作弊。測試是你的規格,規格不該在「讓程式碼更好看」的時候被偷改。
5. 測試之間有依賴。 每個測試應該獨立執行。如果 test_A 失敗導致 test_B 也失敗,表示它們共用了可變狀態。跟 Claude Code 說:「確保每個測試用獨立的 fixture,不要共用物件。」
什麼時候不該用 TDD
有些人的文章會告訴你 TDD 適用於所有場景。這不是真的。
探索性的 prototype 不適合。你還在搞清楚「要做什麼」的時候,先寫測試等於在還不知道目的地的情況下規劃路線。先讓 Claude Code 快速做一個 prototype,確認方向對了,再回頭補測試。
UI 互動邏輯很難純 TDD。按鈕點下去的視覺回饋、動畫、排版——這些用單元測試驗證不了。用 E2E 測試(Playwright、Cypress)比較實際。
一次性腳本也不需要。寫一個跑完就刪的資料遷移腳本,不需要花時間寫測試。直覺判斷:如果這段程式碼兩週後還會存在,就值得寫測試。不會的話,省下來的時間更值錢。
把 TDD 變成習慣的最小可行改變
不需要整個專案從頭改成 TDD。挑一個你接下來要做的新功能,只對這個功能試一次完整的 Red-Green-Refactor 循環。
跟 Claude Code 合作的時候,對話的開頭從「幫我寫 XXX」改成「幫我寫 XXX 的測試」。就這一個改變。
做完之後你會發現兩件事。第一,AI 產出的程式碼品質明顯提升,因為測試消除了模糊性。第二,你對程式碼的信心提高了,因為任何時候都可以跑測試確認「目前為止做的東西都是對的」。
這個信心的差別,在專案越來越複雜的時候會越來越明顯。有測試保護的程式碼可以放心重構。沒有的只能小心翼翼地加東西,祈禱不會弄壞已有的功能。
學完 TDD 之後,自然的下一步是看 Claude Code 的 Sub-agents 和 Agent Teams 怎麼跟測試驅動的工作流整合——讓一個 agent 寫測試、另一個 agent 寫實作、第三個做 code review。但那是另一篇文章的事了。










