我還記得當我第一次得到自動測試的 bug 時的情況。在一次大會上,當我做完叫做 Bitter Java 的演講之后,Mike Clark(Java 社區(qū)的自動測試大師,性能調(diào)整工具 JUnitPerf 的作者(請參閱 參考資料),現(xiàn)在是 Ruby on Rails 專家)走近我。Mike 告訴我有一種方法可以通過自動測試改進我的演講。在那次大會的剩余時間里,我跟著他四處走,看到了我能看到的盡可能多的他的測試會議。我開始使用他推薦的技術,并對把紅條(代表測試失。┳兂删G條(代表測試通過)上了癮。自動測試改變了我思考軟件開發(fā)的方式。
關于本系列
在 跨越邊界 系列中,作者 Bruce Tate 提出了這樣一個觀點:如今的 Java 程序員可以通過學習其他方法和語言得到很好的其他思路。自從 Java 明顯成為所有開發(fā)項目的佳選擇以來編程前景已經(jīng)改變。其他的框架正影響構建 Java 框架的方式,從其他語言學到的概念可以影響您的 Java 編程。您編寫的 Python(或 Ruby、Smalltalk ... )代碼可以改變您處理 Java 編碼的方式。
本系列為您介紹與 Java 開發(fā)根本不同,但也可以直接應用于 Java 開發(fā)的編程概念和技術。在一些例子中,需要對技術進行集成以利用它。在另外一些例子中,您將能夠直接應用這些概念。單獨的工具不及其他語言和框架能夠影響 Java 社區(qū)中的開發(fā)人員、框架甚至基本方法的思想那么重要。
Java 社區(qū)有自動測試的 bug。坦白地說,我們別無選擇。競爭壓力迫使許多公司編寫越來越多的代碼,而測試人員越來越少,同時每個開發(fā)人員的又必須有更高的生產(chǎn)率。如果不進行自動測試,得到測試的內(nèi)容會更少,面對現(xiàn)代應用程序不斷增長的復雜性,較少的測試不是一個可行的選擇方案。
在過去十年中,我們已經(jīng)看到了對測試工具和技術的研究。JUnit 和 TestNG 都是支持自動單元測試的工具,而且由日常的開發(fā)人員所驅(qū)動。Selenium 是改進集成和功能測試的工具。一套稱作敏捷技術 的新開發(fā)過程告訴人們要更加重視自動測試,不要太多地依賴正式的設計工具,將它們作為提高質(zhì)量的惟一工具。Java 社區(qū)已經(jīng)走了很長的路。 (請參閱 參考資料,獲得這里討論的工具與技術的附加信息。)
其他編程社區(qū)也有 bug 工具, 其中一些社區(qū)使用的自動測試要比 Java 開發(fā)人員還有多,他們使用自動測試經(jīng)驗有完全不同的原因:
Smalltalk 程序員使用自動測試已經(jīng)幾乎有 30 年的時間了,所以通過動態(tài)類型化語言使用的一些技術更加先進。
集成框架的開發(fā)人員的優(yōu)勢是了解框架元素的結構和組合。有些框架,例如 Ruby on Rails,能夠生成測試用例,而且在默認情況下提供測試特性。
具有高級元編程(metaprogramming)能力的語言,例如 Ruby and Lisp,允許使用其他語言不支持的一些測試技巧,例如更容易訪問 mock 對象。
在這一篇和下一篇文章中,將全面理解在 Ruby on Rails 集成開發(fā)框架中的測試方式。第 1 部分側重于測試模型對象,并提供一些從 Rails 獲得啟發(fā)的策略,可以用這些策略使 Java 單元測試更有效。第 2 部分把更多時間花在功能測試和集成測試上。作為 Java 程序員,您對一些概念可能比較熟悉,特別是在測試的時候,而其他一些概念可以拓展您的理解。
補漏
在這個系列的 前一期 中,了解了動態(tài)類型化會帶來某些 bug 種類,靜態(tài)類型化語言將在編譯時捕捉到這些 bug。清單 1 的 Ruby 代碼片段包含四個不同的 bug,這四個 bug 在運行時之前都不會顯露出來:
清單 1. 帶 bug 的 Ruby 代碼
position = "2" #string, where a number was intended
position = positoin + 4 #position is misspelled, evaluates to 0
puts "The position is:" +
position.to_string #The method should be to_s
如果編譯器能夠捕捉 bug,那么這類 bug 解決起來是小菜一碟,但是如果依賴解釋器,那么管理這些 bug 困難得多。為了處理這些微妙的錯誤,動態(tài)語言的用戶長期以來一直依賴于自動測試。在進行測試的時候,比起其他語言,動態(tài)語言及其集成環(huán)境在一般意義和特殊意義上都具有顯著的優(yōu)勢:
語言更簡潔。測試基本上是腳本編程,許多好的腳本語言都是動態(tài)類型化的。
集成環(huán)境支持的假設可以讓集成測試更容易,也可能更強大。在 Rails 環(huán)境中將看到一些示例。
動態(tài)語言允許使用更松散的耦合,使一些測試格式更容易實現(xiàn)。
在了解動態(tài)語言開發(fā)人員為什么這么熱衷于測試之后,現(xiàn)在是構建一個需要一些真正測試的實際應用程序的時候了。
構建一個快速 Rails 應用程序
為了進展得快些,我采用了一個保存山地摩托車路線數(shù)據(jù)庫的 Rails 應用程序。我將模型的幾個測試放在一起。如果想和我一起編寫代碼,那么所有需要的工具是一個數(shù)據(jù)庫引擎(我使用的是 MySQL)和 Ruby on Rails 1.1 或更新版本(請參閱 參考資料)。第一步是創(chuàng)建 Rails 項目。在命令提示符下輸入 rails trails 命令,清單 2 顯示了命令和結果:
清單 2. 構建 Rails 應用程序
> rails trails
create
create app/controllers
create app/helpers
create app/models
create app/views/layouts
...partial results deleted...
create test/fixtures
create test/functional
create test/integration
create test/mocks/development
create test/mocks/test
create test/unit
create test/test_helper.rb
...partial results deleted...
create config/environment.rb
create config/environments/production.rb
create config/environments/development.rb
create config/environments/test.rb
...partial results deleted...
create log/server.log
create log/production.log
create log/development.log
create log/test.log