就象我們在前一個測試里面做的一樣,讓我們設法使這個測試通過。為了達到這點,我們必須提供bite()方法,由于我們的測試定義了bite()方法需要如何工作,我們只需要開發它,不再需要思考它應該怎么樣。這個是TDD的另一個核心概念:測試定義了代碼行為。
下面的bite()方法可以使得測試通過:
function bite($needle, $haystack) {
if(preg_match($needle, $haystack, $match)) {
return $match['0'];
}
}
在你的Biter類增加bite()方法,然后再次運行測試?,F在應該通過了,產生了下面的畫面:
讓我們重溫一下剛才我們所做的。我們沒有立刻建立bite()方法,我們先為此創建了一個測試,在那之后我們再提供bite()方法。這個就是TDD提倡的:先測試,后開發。
移除匹配的部分
我們現在還沒有完全完成,因為我們的Biter類有第二個需求:它需要把匹配的部分從原始的字符串中移除。為此讓我們再寫一個測試:
function testPatternMatchIsRemovedFromHaystack() {
$biter =& new Biter;
$haystack = 'foobar';
$biter->bite('/foo/', $haystack);
$this->assertEqual($haystack, 'bar', 'Removed matched part [%s]');
}
我們還是使用assertEqual()方法去斷言兩個變量完全相同,只是這次我們是去檢查匹配部分是否已經被移除。
運行上面的測試,將得到下面的輸出:
現在我們必須使得這個測試通過。這個做起來很簡單,不過假設我們不寫這個測試,而是通過修改其他測試來讓這個測試通過,這樣可能可以少些測試代碼。怎么樣,聽起來不錯?其實是錯誤的!
永遠不能為了讓某一個測試更容易通過而去修改其他的測試!
哪些其他的測試可能是為了特定需求的結果創建的。你實際運行的腳本可能會依賴于那些測試所通過的特定函數。如果你開始修改其他的測試,你就會失去TDD的所有優勢。這就是為什么你永遠不能為了更容易通過某個測試而去修改其他測試的原因。
讓我們回到我們的Biter類。我們如何能讓這個測試通過?我們必須修改傳遞進來的字符串,就好像我們處理通過引用的方式傳遞的參數。修改過的bite()方法看上去象下面這樣:
function bite($needle, &$haystack) {
if(preg_match($needle, $haystack, $match)) {
$haystack = str_replace($match['0'], '', $haystack);
return $match['0'];
}
}
把它放入你的Biter類,然后運行測試。你看到什么?全部都是綠色!
現在我們滿足了Biter類的所有需求,我們可以開始做我們的腳本里面的其他類,開發起來和我們開發Biter類一樣。同時你還能得到另一個好處,就是以后你可以再運行Biter類的測試以便確認它的功能依然正確(這將有效的避免開發過程中偶然的錯誤修改)。
結論
本文中我演示了測試驅動開發如何工作。我們只是構造了一個真實的簡單的類,它非常容易去使用TDD方法,不過做為介紹還是不錯的選擇。
值得注意的是TDD需要主要焦點的轉移,因此它很難推行,它使得開發過程完全不同以往。我可以給出的最好建議是堅持嘗試TDD,最終你會迷戀它。一旦習慣了,你再也不會用其他的方法。
如果你想了解文中的示例項目或者想得到更多的示例,可以看看SitePoint 論壇的相關討論。非常感謝Noel Darlow使得本文得以呈現,并且提供了本文的大部分示例和信息。
如果你對本文有任何問題和建議,歡迎在PHPit論壇與我們討論。