捕獲 bug
我還記得當我第一次得到自動測試的 bug 時的情況。在一次大會上,當我做完叫做 Bitter Java 的演講之后,Mike Clark(Java 社區的自動測試大師,性能調整工具 JUnitPerf 的作者(請參閱 參考資料),現在是 Ruby on Rails 專家)走近我。Mike 告訴我有一種方法可以通過自動測試改進我的演講。在那次大會的剩余時間里,我跟著他四處走,看到了我能看到的盡可能多的他的測試會議。我開始使用他推薦的技術,并對把紅條(代表測試失。┳兂删G條(代表測試通過)上了癮。自動測試改變了我思考軟件開發的方式。
![]() |
|
Java 社區絕對有自動測試的 bug。坦白地說,我們別無選擇。競爭壓力迫使許多公司編寫越來越多的代碼,而測試人員越來越少,同時每個開發人員的又必須有更高的生產率。如果不進行自動測試,得到測試的內容就會更少,面對現代應用程序不斷增長的復雜性,較少的測試不是一個可行的選擇方案。
在過去十年中,我們已經看到了對測試工具和技術的研究。JUnit 和 TestNG 都是支持自動單元測試的優秀工具,而且由日常的開發人員所驅動。Selenium 是改進集成和功能測試的工具。一套稱作敏捷技術 的新開發過程告訴人們要更加重視自動測試,不要太多地依賴正式的設計工具,將它們作為提高質量的惟一工具。Java 社區已經走了很長的路。 (請參閱 參考資料,獲得這里討論的工具與技術的附加信息。)
其他編程社區也有 bug 工具, 其中一些社區使用的自動測試要比 Java 開發人員還有多,他們使用自動測試經驗有完全不同的原因:
- Smalltalk 程序員使用自動測試已經幾乎有 30 年的時間了,所以通過動態類型化語言使用的一些技術更加先進。
- 集成框架的開發人員的優勢是了解框架元素的結構和組合。有些框架,例如 Ruby on Rails,能夠生成測試用例,而且在默認情況下提供測試特性。
- 具有高級元編程(metaprogramming)能力的語言,例如 Ruby and Lisp,允許使用其他語言不支持的一些測試技巧,例如更容易訪問 mock 對象。
在這一篇和下一篇文章中,將全面理解在 Ruby on Rails 集成開發框架中的測試方式。第 1 部分側重于測試模型對象,并提供一些從 Rails 獲得啟發的策略,可以用這些策略使 Java 單元測試更有效。第 2 部分把更多時間花在功能測試和集成測試上。作為 Java 程序員,您對一些概念可能比較熟悉,特別是在測試的時候,而其他一些概念可以拓展您的理解。
![]() ![]() |
![]()
|
補漏
在這個系列的 前一期 中,了解了動態類型化會帶來某些 bug 種類,靜態類型化語言將在編譯時捕捉到這些 bug。清單 1 的 Ruby 代碼片段包含四個不同的 bug,這四個 bug 在運行時之前都不會顯露出來:
清單 1. 帶 bug 的 Ruby 代碼
|
如果編譯器能夠捕捉 bug,那么這類 bug 解決起來是小菜一碟,但是如果依賴解釋器,那么管理這些 bug 就困難得多。為了處理這些微妙的錯誤,動態語言的用戶長期以來一直依賴于自動測試。在進行測試的時候,比起其他語言,動態語言及其集成環境在一般意義和特殊意義上都具有顯著的優勢:
- 語言更簡潔。測試基本上是腳本編程,許多最好的腳本語言都是動態類型化的。
- 集成環境支持的假設可以讓集成測試更容易,也可能更強大。在 Rails 環境中將看到一些示例。
- 動態語言允許使用更松散的耦合,使一些測試格式更容易實現。
在了解動態語言開發人員為什么這么熱衷于測試之后,現在是構建一個需要一些真正測試的實際應用程序的時候了。
![]() ![]() |
![]()
|
構建一個快速 Rails 應用程序
為了進展得快些,我采用了一個保存山地摩托車路線數據庫的 Rails 應用程序。我將模型的幾個測試放在一起。如果想和我一起編寫代碼,那么所有需要的工具就是一個數據庫引擎(我使用的是 MySQL)和 Ruby on Rails 1.1 或更新版本(請參閱 參考資料)。第一步是創建 Rails 項目。在命令提示符下輸入 rails trails
命令,清單 2 顯示了命令和結果:
清單 2. 構建 Rails 應用程序
|
Rails 除了生成空項目什么都沒做,但是可以看到它正在為您工作。清單 2 創建的目錄中包含:
- 應用程序目錄,包括模型、視圖和控制器的子目錄
- 單元測試、功能測試和集成測試的測試目錄
- 為測試而明確創建的環境
- 測試用例結果的日志
因為 Rails 是一個集成環境,所以它可以假設組織測試框架的最佳方式。Rails 也能生成默認測試用例,后面將會看到。
現在要通過遷移創建數據庫表,然后用數據庫表創建新數據庫。請鍵入 cd trails
進入 trails 目錄。然后生成一個模型和遷移(migration),如清單 3 所示:
清單 3. 生成一個模型和遷移
|
注意,如果使用 Windows,就必須在命令前加上 Ruby
,這樣命令就變成了 ruby script/generate model Trail
。
如清單 3 所示,Rails 環境不僅創建了模型,還創建了遷移、測試用例和測試 fixture。稍后將看到 fixture 和測試的更多內容。遷移讓 Rails 開發人員可以在整個開發過程中處理數據庫表中不可避免的更改(請參閱 跨越邊界:研究活動記錄)。請編輯您的遷移(在 001_create_trails.rb 中),以添加需要的列,如清單 4 所示:
清單 4. 添加列
|
您需要創建和配置兩個數據庫:trails_test
和 trails_development
。如果想把這個代碼投入生產,那么還需要創建第三個數據庫 trails_production
,但是現在可以跳過這一步。請用數據庫管理器創建數據庫。我使用的是 MySQL:
清單 5. 創建開發和測試數據庫
|
然后編輯 config/database.yml 中的配置,以反映數據庫的優先選擇。我的配置看起來像這樣:
清單 6. 將數據庫適配器添加到配置中
|
現在可以運行遷移,然后把應用程序剩下的部分搭建(scaffold)在一起:
清單 7. 遷移和搭建
|
再次注意,Rails 已經為您創建了測試用例?蚣懿粌H為這個簡單的小程序生成了視圖和控制器,而且還生成了有助于測試用戶界面的功能性測試。
![]() ![]() |
![]()
|
對 Rails 應用程序進行單元測試
現在是運行一些測試的時候了。請看第一個測試,它已經在 test/unit/trail_test.rb 中寫好了:
清單 8. 第一個測試
|
確實,這個測試用例算不了什么,但您可以從中看出如何構架測試代碼,而且自己的測試用例的模板也已經就位。請運行測試,如清單 9 所示(包括結果):
清單 9. 運行第一個測試
|
測試用例失敗,但是請看輸出。第一行執行測試。第三行 EE
顯示測試的結果。如果測試用例通過,會得到 “.
” 字符。如果測試用例產生錯誤,會看到 E
。如果某個斷言不是 true,那么將看到 F
。接下來,可以看到所請求的全部測試都將完成,以及完成這些測試需要的時間。最后,將看到每個失敗的詳細原因。在這個示例中沒有表,這是有一定原因的,因為在測試數據庫中還沒有創建任何表。通過將開發方案復制到測試環境,再重新運行測試,可以修復錯誤,如清單 10 所示:
清單 10. 復制方案,重新運行測試
|
這樣更好。但是測試還是太簡單,所以是構建一個真正的測試用例的時候了。請添加下面這個新測試用例 test_truth
,如清單 11 所示:
清單 11. 添加測試用例
|
這個代碼驚人的緊湊。只需要鍵入上述代碼以及兩個斷言,就可以操縱持久模型。這種經濟的投入正是腳本語言在其他環境中如此流行的原因。測試也是需要經濟投入的地方。
現在可以運行測試用例,您將看到兩個新斷言顯示在測試報告中。使用 Ruby 時,只需保存并編譯測試即可。清單 12 顯示了測試運行的結果:
清單 12. 測試結果
|
Fixture 和回滾
![]() |
|
有三個問題影響了對數據庫支持代碼的測試。它們都與兩個特性有關:性能和重復性。與內存中的操作相比較,數據庫調用的性能是非常低的。如果測試運行需要太長時間,那么您可能就不想運行它們了。另一個問題是一個測試用例對另一個測試用例的影響。因為數據庫調用在性質上是持續的,所以要把一個測試在數據庫中的變化與另一個數據庫中的隔離開。最后的問題是前兩個問題的組合。為了讓數據庫測試用例可重復而增加設置和拆卸的負擔時(為每個新的測試用例添加記錄、運行測試并刪除這些記錄),帶來的開銷可能是讓人無法接受的。與這種開銷相比,測試用例開銷簡直是小巫見大巫。
Ruby on Rails 用 fixture 和事務回滾來幫助解決這些問題。在 Rails 中,一個 fixture 就是一個包含測試用例數據的文件。在創建這個簡單應用程序時,同時還創建了一個開發數據庫和一個測試數據庫。創建開發數據庫是很正常的;但是您可能不想讓生產代碼和開發環境共享同一個數據庫。而創建測試數據庫因為另一個原因也很重要。每個測試都在測試用例開始時裝入 fixture 中的測試數據。然后,測試用例對數據庫進行修改,并測試這些修改的結果。最后,Rails 回滾這些變化,將數據庫返回到測試方法運行之前的狀態。
現在要制作一個測試 fixture 并為它編寫一個測試。請編輯 test/fixtures/trails.yml 文件,添加一個記錄,如清單 13 所示:
清單 13. 添加記錄
|
清單 13 使用叫做 YAML 的語言,這個語言描述結構化的數據(請參閱 參考資料)。此文件對空格很敏感,所以該當用空格代替制表符并完全按原樣鍵入數據項時,請確保刪除了所有尾部空格。
同樣,還要把這個測試用例添加到 trails_test.rb 中:
|
同樣,可以用 5 個 passing 斷言運行這些測試。如果您愿意,還可以按名稱引用每個 fixture。例如,要根據名為 first
的 fixture 來創建對象,可以使用 Ruby 代碼 trails[:first]
。讓 fixture 對所有測試用例或只對需要它們的測試用例可用,這極大地簡化了創建或毀壞數據庫數據所需要的代碼。
![]() ![]() |
![]()
|
在 Java 編程中測試
知道了測試在其他語言中如何發生,就可以改進在 Java 平臺上進行測試的方式。具體地說,使用這些想法中的一項或多項可以對測試產生顯著而直接的影響:
- 可以把測試用例的生成添加到任何現有代碼生成當中。Ruby on Rails 通過在默認情況下創建一些簡單的測試用例來取得了巨大優勢,您也可以這么做。
- 可以用事務-回滾技術讓數據支持的測試運行得更快。Spring 框架有一些現有的攔截器,可以讓這項技術易于使用。
- 實際上可以用動態語言驅動測試。Jython、Ruby 和 Groovy 是三個實際可能。
如果覺得愿意采用其他語言進行測試,那么可以使用某種 JVM 語言,例如 JRuby(請參閱 參考資料)。JRuby 還沒有高級到可以運行 Ruby on Rails,但是它是 Java 應用程序卓越的測試平臺。只是作為嘗試,JRuby 的開發人員 Charles O'Nutter 提供了以下測試 EJB 的示例:
清單 14. 用 JRuby 測試 EJB 組件
|
可以看到,用 Ruby 編寫執行 Java 代碼的測試用例實際上非常容易。在這個示例中,Ruby 代碼發現一個 EJB 組件,并為用戶返回的 bean 提供了一些斷言。測試用例當然比多數 Java 測試都容易,使用 Ruby 編寫測試用例是一個獲得更高的生產率和速率的一種好方法。我還看到針對 Jython 或 Groovy 的類似策略(請參閱 參考資料)。
第 2 部分將進一步深入查看 Rails 的測試,包括運行更高層次測試(叫做功能測試和集成測試)的代碼。
文章來源于領測軟件測試網 http://www.kjueaiud.com/
版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
技術支持和業務聯系:info@testage.com.cn 電話:010-51297073
老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月