章節概述#
本章的目標是讓待辦清單上的 5 CHF * 2 = 10 CHF 測試通過。這看起來是往混合貨幣運算邁進的必要前提——我們需要一個類似 Dollar 的 Franc 物件。Kent Beck 在本章坦率地承認:為了速度,他選擇了複製貼上。
從小測試開始#
待辦清單上最有趣的項目(混合貨幣加法)跨度太大,無法一步到位。因此,先退一步,建立一個更小的測試作為踏腳石:
public void testFrancMultiplication() {
Franc five = new Franc(5);
assertEquals(new Franc(10), five.times(2));
assertEquals(new Franc(15), five.times(3));
}這個測試直接複製自 Dollar 的測試,只是把 Dollar 換成了 Franc。(作者也提到,前一章簡化測試的成果在這裡立刻發揮了作用。)
用複製貼上快速通過測試#
讓這個測試通過的最短路徑是什麼?直接把 Dollar 的程式碼複製一份,把名字改成 Franc:
class Franc {
private int amount;
Franc(int amount) {
this.amount = amount;
}
Franc times(int multiplier) {
return new Franc(amount * multiplier);
}
public boolean equals(Object object) {
Franc franc = (Franc) object;
return amount == franc.amount;
}
}測試立刻通過,甚至連「讓它編譯通過」這一步都省了。
TDD 循環的五個階段#
作者預料到讀者對複製貼上的不滿,特別強調了 TDD 循環的完整五步:
- 寫一個測試
- 讓它編譯通過
- 執行測試,確認它失敗
- 讓它通過
- 消除重複
前四步追求的是速度——盡快進入已知狀態、確認新功能可行。在這個階段,任何「罪過」都可以忍受。但循環必須走完第五步:消除重複(Remove duplication)。
重點: 「Make it run, make it right.」——先讓它能跑,再讓它正確。四條腿的 Aeron 椅子會倒。沒有第五步,前四步就不完整。好的設計在對的時機出現。
更新後的待辦清單#
通過測試後,清單上劃掉了 5 CHF * 2 = 10 CHF,但也新增了兩項技術債:
5 CHF * 2 = 10 CHF- Dollar/Franc duplication(新增)
- Common equals(新增)
- Common times(新增)
本章小結#
- 面對太大的測試時,發明一個較小的、代表進展的測試
- 用無恥的複製貼上來撰寫測試
- 更過分地,直接批量複製模型程式碼來讓測試通過
- 承諾在消除重複之前絕不收工