本章內容
- 實行測試驅動開發(TDD)的好處
- TDD的核心:紅—綠—重構循環週期
- JUnit,公認的Java測試框架
- 四種測試替身:虛設、偽裝、存根和模擬
- 用內存數據庫測試DAO代碼
- 用Mockito模擬子系統
- 使用Scala測試框架ScalaTest
測試驅動開發(TDD)進入軟件開發行業已經有相當長的時間了。它的基本前提是在編寫真正的功能實現代碼之前先寫測試代碼,然後根據需要重構實現代碼。比如要寫一段拼接兩個String
對像("foo"
和"bar"
)的實現代碼,應該先寫測試代碼(測試結果必須等於"foobar"
),以確保你能判斷實現是否正確。
很多開發人員都知道JUnit,也會在開發時不定期用到它。但他們一般是寫完實現代碼之後才編寫測試代碼,因此體會不到TDD的益處。
儘管TDD的概念看起來非常普及,但實際上很多開發人員並不清楚為什麼要採用TDD。對於很多開發人員來說,「為什麼要寫測試驅動代碼以及有什麼好處」一直是個問題。
我們認為消除恐懼和不確定性是編寫測試驅動代碼的重要原因。Kent Beck(JUnit測試框架的發明人之一)在Test-Driven Development: by Example1(Addison-Wesley Professional,2002)一書中對此總結得很好:
- 恐懼會讓你小心試探;
- 恐懼會讓你盡量減少溝通;
- 恐懼會讓你羞於得到反饋;
- 恐懼會讓你脾氣暴躁。
1 中文版《測試驅動開發》已由中國電力出版社於2004年出版。——編者注
TDD可以祛除恐懼,讓優秀的Java開發者變得更加自信、善於溝通、樂於接受並更加快樂。換句話說,TDD能幫你擺脫下面這種心態:
- 在開始新工作時,「我不知道從哪裡開始,所以只好將就著做一些修改」;
- 在修改已有代碼時,「我不知道現有代碼怎麼運行,所以我私下認為不能碰它們」。
TDD帶來的很多好處並不會馬上顯現:
更清晰的代碼——只寫需要的代碼;
更好的設計——有些開發人員管TDD叫測試驅動的設計;
更出色的靈活性——TDD鼓勵按接口編碼;
更快速的反饋——不會直到系統上線才知道bug的存在。
剛入門的開發人員有時認為TDD不是「普通」開發人員用的技術,這是他們採用TDD的一個障礙。他們的感覺是只有那些想像中的「敏捷派」或其他神秘組織的成員才會用TDD。這種認識完全錯誤,我們會在後面解釋。TDD是給所有開發人員使用的技術。
另外,敏捷和軟件工藝運動都是為了讓開發人員活得更輕鬆。它們肯定不會拒絕別人使用TDD或其他任何技術。
本章首先解釋TDD背後的基本思想紅—綠—重構循環,然後介紹Java測試框架中的主力JUnit,並用一個簡單的例子來闡明其原則。
敏捷宣言和軟件工藝運動
敏捷運動(http://agilemanifesto.org/)已經開展很長時間了,可以說部分改善了軟件開發行業。很多偉大的技術,比如TDD,都是這項運動所倡導的。軟件工藝是一項新運動,鼓勵參與者編寫清晰的代碼(http://manifesto.softwarecraftsmanship.org/)。
我們喜歡取笑實行敏捷和軟件工藝運動的弟兄們。可是,我們自己甚至也擁護它(大多數時候都是如此)。但優秀的Java開發人員,請不要忽視那些對你有用的東西。TDD是一項軟件開發技術,僅此而已。
接下來,我們會介紹TDD使用的四大類偽裝對象。它們能簡化受試代碼和第三方類庫中代碼的隔離,或隔離數據庫之類的子系統行為,所以它們很重要。隨著依賴項變得越來越複雜,偽裝對象也要變得越來越聰明。最終我們會介紹模擬和Mockito類庫,它是一個流行的模擬工具,可以讓開發人員在不受外部系統影響的環境下進行測試。
開發人員非常熟悉Java測試框架(特別是JUnit),並且一般都有用它們編寫測試代碼的經驗。但對於如何用測試驅動Scala、Clojure等新語言,你可能毫無頭緒。因此我們會介紹Scala測試框架ScalaTest,以確保你能在開發Scala代碼時應用TDD。
讓我們開始瞭解這個有點奇怪的TDD吧。