在 Day 11,我們行雲流水地完成了整個 FizzBuzz Kata,深刻地體會到,TDD 是如何透過一個個微小的「紅-綠-重構」循環,安全、自信地引導開發者應對逐漸增加的邏輯複雜性。
FizzBuzz 的規則是固定的,但真實世界的軟體開發,需求卻是「演進」出來的。我們經常會遇到這樣的場景:
這個功能很棒,但能不能再增加一個...
為了磨練我們應對這種「增量式需求變更」的能力,今天,我們再來做一個 TDD 領域裡的經典 Kata: 字串計算機 (String Calculator)。
今天的目標: 理解字串計算機 Kata 的規則,學習如何用 TDD 的思維來拆解它的初始需求。
這個 Kata 的需求是從一個極其簡單的起點,一步步變得複雜起來的,它巧妙地模擬了真實的軟體開發過程。
我們要建立一個 Add 方法,它接收一個字串參數,並回傳一個 int 型別的結果。這個方法的功能將會逐步增加。
TDD 的思考藝術:從「最微不足道」的起點開始
面對這一系列規則,我們應該先從哪裡下手? 以TDD的角度去看,答案永遠是:找到那個最簡單、最核心、甚至看起來有些「微不足道」的規則,讓我們檢視一下初始規則:
哪一個最簡單?毫無疑問是規則 2。
這就是我們 TDD 旅程的第一步。我們的第一個測試目標就此誕生:
「當呼叫 Add("") 時,函式應回傳 0 和一個 nil 的 error。」
我們將完全忘掉其他所有規則,只專注於這個微小的目標,這就是 TDD 幫我們聚焦、簡化問題的方式。
與 FizzBuzz 一樣,我們需要為這個新的 Kata 建立一個獨立的套件。
go-tdd-kata
下,建立一個新的資料夾 stringcalc
。stringcalc
資料夾中,建立兩個新檔案:
你的專案結構現在看起來應該是這樣:
go-tdd-kata/
├── go.mod
├── fizzbuzz/
│ ├── fizzbuzz.go
│ └── fizzbuzz_test.go
├── stringcalc/
│ ├── stringcalc.go <-- 新檔案
│ └── stringcalc_test.go <-- 新檔案
└── main.go
package stringcalc
// Add 是一個佔位函式,我們將透過 TDD 來實現它
func Add(numbers string) (int, error) {
return 0, nil // 暫時回傳一個預設值
}
注意: 我們遵循了規則 1 的方法簽名,它回傳一個 int 和一個 error。
package stringcalc
import "testing"
func TestStringCalculator(t *testing.T) {
// 我們將在這裡,從明天開始填寫我們的測試案例
}
回到終端機,在根目錄執行 go test -v ./...
,你應該會看到所有套件都被成功識別。
ok go-tdd-kata/fizzbuzz 0.314s
? go-tdd-kata/stringcalc [no test files]
注意:你可能會看到 stringcalc
的測試結果是 [no test files]
或 ok
,這取決於 Golang 的版本和快取,只要沒有報錯,就代表我們的結構是正確的。
今天,我們成功地從一個 Kata 過渡到下一個更具挑戰性的 Kata。我們沒有寫任何一行真正的邏輯,但完成了至關重要的準備工作:
舞台已經為「字串計算機」搭建完畢,我們已經確定了第一個要攻擊的目標。
預告:Day 13 - 字串計算機實戰 (一) - 處理空字串與單一數字。明天,我們將開始撰寫字串計算機的程式碼,一樣地從「紅燈」開始,為「空字串應回傳 0」這個最基本的需求寫測試,並完成相應的 TDD 循環。