超越單元測試的擴展
![]() |
|
在這由兩部分組成的迷你系列的 第 1 部分 中,了解了如何用動態語言促進單元測試。本文將展示集成環境在功能測試和集成測試中的優勢。單元測試包括對小的代碼片斷(例如方法)的測試,而且經常要把它們與周圍的元素隔離開。功能測試和集成測試所測試的應用程序部分越來越多。功能測試用于測試單一特性(通常涉及一個接口)、執行任務的業務代碼,以及與中間件服務交互的代碼(例如數據庫)。集成測試用于測試應用程序的多個不同特性。(功能測試在不太嚴謹的情況下通常也被稱為集成測試。)
Java 開發人員在解決單元測試問題上已經獲得了令人注目的成果,但在集成測試上則沒有帶來太多令人興奮的消息。多數 Java 測試框架(如 JUnit 或 TestNG)主要側重于單元測試。Java 編程中缺乏集成測試框架的一個原因是缺乏集中的架構或開發哲學。在后面的小節中,我將繼續使用 Ruby on Rails 示例,這次的重點放在功能測試和新的 Rails 集成測試框架上。您將看到,在使用集成測試框架時,進行測試要容易得多。
運行測試
如果還沒有閱讀 第 1 部分,那么請先閱讀它。然后,如果想跟隨這篇文章一起編寫代碼,那么請確保您已經獲得一個可工作的 Rails 應用程序。在第 1 部分中,實現了一個簡單的單元測試和幾個 fixture。如果您跟隨第 1 部分一起編寫了代碼,但是記不清是否使應用程序處于工作狀態,那么您可以利用測試用例,先切換到項目目錄,然后運行 rake
即可。清單 1 顯示了我的結果:
清單 1. 用 rake 運行所有測試
|
可以看到有一些問題存在:rake
生成了 16 個錯誤。跟蹤顯示,Rails 無法建立連接。我忘記啟動數據庫引擎了。我將啟動數據庫引擎,然后再次運行 rake
。這次我得到了清單 2 所示的結果:
清單 2. 在 rake 內通過測試
|
這樣就好多了。測試正常運行,而我們準備構建更多測試用例。如果仔細查看清單 2 就會發現,rake
生成了兩組結果。第一組(第 1 部分的單元測試)看起來應當熟悉。下一組是從框架中自動生成的功能測試。
![]() ![]() |
![]()
|
控制器和視圖快速入門
在查看測試代碼之前,需要對 Rails 的用戶界面層有更好的理解。在第 1 部分中,用 script/generate scaffold Trail Trails
生成框架代碼時,Rails 根據數據庫的內容為應用程序創建了一個控制器和系列視圖?刂破鞯拇a位于 app/controller/trails_controller.rb,視圖則全部位于 app/views/trails 下的不同目錄中。這個應用程序包含:
- 默認 Web 頁面實現,顯示路線(trail)列表(叫做
list
) - 路線的細節信息的顯示頁面
- 路線的通用表單
- 創建或編輯路線的頁面
要了解這些是如何組合在一起的,請參見 trails_controller.rb 中的 list
方法,如清單 3 所示:
清單 3. app/controllers/trails_controller.rb 中的部分代碼清單
|
傳入的超文傳輸協議(HTTP)請求進入控制器。(HTTP 是支持瀏覽器、Rails 和所有基于瀏覽器的應用程序的底層協議)。在這篇文章后面,您將看到功能測試如何通過使用 HTTP 命令來調用功能測試用例。清單 3 的代碼設置了 Rails 顯示線路的分頁列表時需要的實例變量。視圖需要一個分頁器對象,即 Rails 分配給 @trail_pages
的分頁器對象,還需要 @trails
中的路線列表。默認情況下,Rails 使用與控制器方法相同的名稱呈現視圖。要查看視圖,請參閱 app/views/trails/list.rhtml 中的表格定義,如清單 4 所示:
清單 4. list.rhtml 的部分代碼清單
|
Rails 中的視圖策略是:創建一個簡單字符串,然后做一些替換。這個策略叫做建模,它構成了大多數現代 Web 框架的基礎,包括 Java 框架(例如 Tapestry、JavaServer Faces(JSF)、JavaServer Pages (JSP) 和 WebWork)。在這個示例中,Rails 做了以下工作:
- 執行
<%
和%>
之間的代碼段(被稱為語句),并用代碼段的執行輸出替代這一部分。語句可能不存在。
- 執行
<%=
和%>
之間的代碼段(被稱為表達式),并用代碼段返回的值替代這一部分。
- 處理布局、偏好、幫助程序以及其他類型的代碼片斷時。這些特性允許使用不同的復合部件構建復雜的 Web 頁面。在這里,我就不對細節做過多介紹了。
在有了模板策略之后,現在再來看一下 清單 4。您可以看到訪問活動記錄 Trail
模型并用 <% for trail in @trails %>
命令在 @trails
中的每條路線上循環的 list.rhtml 視圖。(您已經填充了控制器中的 @trails
實例變量)。對于每條路線,該視圖都將得到 Trail.content_columns
,它是 trails_development
數據庫中 trails
表的列的列表。然后,該視圖通過在列表中的每個列上進行循環,提供數據庫中每一列的值。trail.send(column_name)
命令把 name
、difficulty
和 description
方法發送給 trail
。
現在是在屏幕上查看結果的時候了。如果回憶一下,應當記得您已經在第 1 部分的示例中鍵入了一些 fixture 形式的測試數據。要把它們加載到開發環境(fixture 默認裝入測試環境)中,則只需鍵入 rake load_fixtures
即可。啟動 Rails 服務器(在 Unix 上用 script/server
,在 Windows 上用 ruby script/server
),把瀏覽器指向 localhost:3000/trails/list 就可以看到結果。在這個 URL 中,trails 是控制器的名稱,list 是動作的名稱,由 list
控制器方法實現。圖 1 顯示了結果:
清單 1. 列出路線

正如所期望的那樣,可以看到一個包含每條路線的名稱、說明和難度的表。接下來,我將介紹 Rails 的功能測試框架如何只通過一條 HTTP put
命令訪問 Web 頁面。
![]() ![]() |
![]()
|
分解功能測試
回憶一下就可以知道,Rails 單元測試只處理模型。Rails 中的功能測試調用 Web 頁面,然后檢查結果,從上到下地測試某一特性(包括模型、視圖和管制器)。這種級別的集成測試很重要,因為可以確保系統的主要元素之間的交互與您對所提供的每個特性的預期一樣。
Rails 的每個功能測試用例都要進行 HTTP put
和 get
。它們調用控制器的動作;控制器訪問模型和視圖,并呈現 Web 頁面和結果。要獲得詳細的工作示例,請參見 Rails 在框架中生成的測試用例:
清單 5. 來自 test/functional/trails_controller_test.rb 的 test_list
|
清單 5 中的測試用例利用 get :list
命令執行了一個簡單的 HTTP get
。然后,測試用例運行了三個斷言:
assert_response :success
:HTTP 命令成功完成。assert_template 'list'
:控制器動作呈現list
模板。assert_not_nil assigns(:trails)
:控制器把@trails
實例變量分配給一些非 null 的值。
使用單元測試框架,如果斷言為 ture,沒有錯誤出現,那么測試用例就通過;否則,測試用例失敗。
test_list
測試用例可以聲明 :success
響應,但是它應當聲明 :redirect
(代表 HTTP 重定向)、:missing
(代表 not_found
),或代表單個 HTTP 返回代碼的整數。請參閱 參考資料,獲得 HTTP 返回代碼的詳盡列表,F在請看 test_create
,它使用了一個 HTTP put
。請將 test_create
更改成如清單 6 所示:
清單 6. 測試表單
|
trails_controller_test.rb 中自動生成的這個測試用例的版本包括 post :create, :trail => {}
,它調用 create
方法,空哈希表表示新路線。這個代碼應當創建一條新路線,該路線有一個所有屬性都為 null 的 Trail
對象。清單 6 修改了代碼,以傳遞代表路線屬性的哈希映射表。這個哈希映射表接口對于在測試框架中指定對象而言非常有用。然后,測試用例用 Trail
模型確保創建了新路線。
清單 5 和清單 6 中的測試用例不像第 1 部分中的單元測試那樣處理每個細節。但是它們可以保證調用了業務邏輯,保證控制器邏輯沒有檢測到任何錯誤,并保證得到了正確的 HTTP 響應。
Rails 還提供了另一種測試用例:集成測試。
![]() ![]() |
![]()
|
集成測試
功能測試用于測試單一特性,而集成測試可能觸及許多不同的頁面。例如,購物車單元測試可以測試出您可能通過模型 API 將一件商品添加到購物車中。購物車的功能測試可以確保您能夠通過登錄某一 Web 頁面將商品添加到購物車中。而集成測試則可以保證能夠登錄、添加商品和結賬。
在 “Running Your Rails App Headless”(請參閱 參考資料)中,Mike Clark(Rails 社區領先的測試專家之一)詳細介紹了集成測試框架。開始進行討論時,他介紹了如何運行沒有 Web 頁面的(即 headless)應用程序。這項功能使得搜集編寫集成測試的足夠信息變得更容易。從 Rails 1.1 開始,可以直接從控制臺調用控制器。不需要瀏覽器,只要調用 app
對象的 put
和 get
方法,就可以訪問應用程序的 Web 頁面。
請啟動控制臺,鍵入清單 7 中的命令,通過 HTTP get
發出列表動作:
清單 7. 從控制臺使用 Rails 集成測試框架
|
在清單 7 中,從控制臺以兩種形式發送請求,調用 trails
控制器的 list
動作。然后,通過與正則表達式 /Emma Long/
匹配,可以看到生成的 HTML 頁面中包含 Emma Long(一條路線)。您可以繼續運行 post
和 get
:
清單 8. 通過 post 實現刪除
|
通過控制臺集成測試 API,現在有了構建集成測試的足夠信息。請使用 script/generate integration_test DestroyAndShow
生成一個集成測試,并將它編輯成清單 9 那樣:
清單 9. test/integration/destroy_and_show.rb
|
這個示例使用的集成框架與前面通過 Rails 控制臺使用的框架相同,使用的斷言模型也與功能測試和單元測試框架的模型相同?梢杂 rake
運行測試用例,也可以單獨運行每個測試用例。通過以一致的方式使用控制臺和集成框架,可以嘗試應用程序的各個方面,獲得控制臺中的結果,并用這些結果在自動測試用例中提供您的斷言。
![]() ![]() |
![]()
|
在 Ruby 中測試與在 Java 語言中測試的對比
現在可以開始查看集成框架中的集成測試有什么不同了。對于這個示例,可以使用 fixture,它們在集成測試框架中工作。斷言和表示想法的方式(例如請求和響應)都有統一的形式。
基本 Ruby 語言中的某些功能讓 Rails 的測試更強大?梢允褂 Ruby 做類似 mock 和存根所做的事。在編寫這篇文章時,我正在使用 Rails 進行一些自動集成測試。我有一個依賴于當前日期的類。我只是打開了用于 Date
的現有 Ruby 類,并重新定義了 today
方法,讓它返回 Date.civil(2, 2, 2006)
,如清單 10 所示:
清單 10. 用 Rails 創建存根
|
對于我的測試用例,我什么都不需要做,F在,不論測試用例什么時候運行,today
都會是美國的假日土拔鼠日。只使用了五行代碼,我就有了一個可工作的存根。在這個示例中,這個 mock 對象只能用于測試用例。如果需要將這個 mock 對象用于多個測試用例,那么可以給這個 mock 對象添加測試和模擬的代碼,并重新使用它。
總之,我對 Ruby 的測試體驗的評價是:非常必要(因為動態語言容易出錯的特性),并且更強大。其中部分力量來自通過 Rails 使得代碼生成、斷言、數據庫支持,以及診斷工具無縫地在一起工作的集成體驗。
但是 Java 技術確實有自己的優勢。在將測試集成到開發環境方面它做得更好,它還有更好的持續集成工具。也可以找到模擬最常見企業特性的更多框架。Java 開發人員有另一個理論優勢:他們可以在沒有數據庫支持的情況下,更容易地運行應用程序。沒有數據庫支持就測試 Rails 應用程序幾乎沒有意義,因為許多 Rails 值是通過元編程(metaprogramming)把 SQL 特性編織起來而得到的。所以,Java 測試套件通常運行得更快,因為套件中的測試用例不需要訪問數據庫。
如果使用 Java 代碼生成,Rails 可以為您提供一些關于如何使用測試生成增強您的代碼生成的好主意。如果正在補充自己的測試框架,那么 Rails 的測試 API 既簡單又漂亮。如果對超越 Java 編程語言感興趣,那么 Rails 可以為輕量級的、數據庫支持的應用程序提供一些真正的價值。
在這個系列的下一篇文章中,我將不再介紹 Rails,而是查看基于 Web 的建模策略。您將看到如何將代碼生成用于動態語言。
文章來源于領測軟件測試網 http://www.kjueaiud.com/
版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
技術支持和業務聯系:info@testage.com.cn 電話:010-51297073
老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月