• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    對復雜的單元測試使用模擬對象

    發布: 2008-3-06 12:35 | 作者: 網絡轉載 | 來源: 網絡轉載 | 查看: 112次 | 進入軟件測試論壇討論

    領測軟件測試網 如今,程序員比以往更多地認識到他們有責任創建編寫較好的單元測試。無論一個開發人員是在進行測試驅動的開發(TDD)還是在編寫代碼后創造單元測試,有一點是十分明顯的,那就是單元測試有助于產出高質量、無缺陷的代碼。

    即便開發人員知道測試的益處,我們也會發現程序員們不愿意測試他們的代碼。他們會列出各種理由,如時間不夠、沒有有效的工具以及在編寫帶有許多有依賴關系的對象的測試方面有問題。

    本期的文章中,我想將重點放在單元測試上,并看看如何解決這些問題。特別地,我想提供一些技巧來說明編寫帶有模擬對象的單元測試是多么容易。

    對于單元測試的常見異議

    在深入探討模擬對象之前,讓我們先來看一下以下兩點異議。

    花費時間太長

    我們很早就認識到這樣一個原則“做事情需要花費時間”,特別當這些事情值得去做。很少的開發人員會懷疑整體測試的價值,因此我們需要考慮如何定義“太長”這個詞的含義。

    開發人員們缺乏耐心,他們想要的是結果。他們喜歡寫代碼、運行代碼然后看結果。從這一點來說,單元測試對他們有幫助。單元測試滿足開發人員們的及時需求,但是許多程序開發人員認為編寫測試占據了他們編寫應用程序代碼的時間,而他們的工作是按照后者計算報酬的。當然如果您僅僅按照程序開發人員在一個特定時間創建的應用程序代碼的行數(或者一些其他方法)來計算的話,這一點是正確的。但是我們必須考慮每行代碼所承載的全部時間。如果每當代碼編譯完成并運行通過我們就停止計算的話,我們可能會忽略掉創建軟件最重要的部分—消除缺陷。在軟件開發周期中越晚發現缺陷,修復缺陷所花費的代價會隨之成倍增長。在開發過程中許多預先的質量檢驗會多占用一點點時間,但是會在以后節約大量時間。這一點已經被許多研究所證實。

    仍有許多程序設計人員認為找出他們代碼中的錯誤是其他一些人的工作。我發現近十年來這種情況已經有了顯著的改進,但是仍有大量的程序人員并沒有為他們的工作負全責,他們也不使用有助于改進他們代碼的工具和技術。在早期的軟件工程課程中我向我的學生們介紹過單元測試。我告訴他們如何使用現代工具編寫測試。我布置了關于編寫單元測試的作業。然而,當給他們機會在工作中采用有效的單元測試時,只有25%的學生這樣做。原因是什么呢?因為他們還沒有意識到測試的重要性。他們的直覺戰勝了理性。他們知道單元測試的價值,但他們選擇不予理會。

    單元測試并不需要花費很長時間,但許多程序設計員認為它需要。作為一名教育工作者,我需要努力地在學生們職業生涯的早期就改變這一認識,并在他們整個學習過程中不斷的加以強化。商業組織必須跟上步伐,在他們雇用畢業生時使得單元測試成為一份寶貴的實踐。

    低效的工具

    這充其量是一個乏味的借口。在今天有很多有效的單元測試工具可供開發人員們使用。不管您使用的是什么程序語言或者其他的開發工具,單元測試工具都可以供您使用。許多工具都是開源或者免費的。

    我選擇 Eclipse 作為我的主要開發環境。在我現有的 Eclipse 配置里可以得到的所有單元測試工具中,我主要使用的是 Junit 測試框架。大多數 Java 設計人員都知道 Junit 并且大概至少使用過一次。JUnit 是 Eclipse 的 Java 開發工具中的一個完整部分。這個平臺使得創建 Junit 測試變得簡單。我只需在瀏覽器包里選擇一個 Java 源文件,并在右擊已選文件時從關系菜單里選擇 New>JUnit Test Case即可。提供的支持包括在測試中為類自動創建測試方式以及更多的東西。運行測試和創建一樣簡單。Eclipse 帶有一個獨立的視圖可以觀察 Junit 測試的結果。

    Eclipse 中集成了大量的單元測試工具。其中許多是基于 Junit 并在性能上有所擴充。我讓我的學生們在面向對象的設計類中使用 Coverlipse 插件程序來檢測他們的測試的代碼覆蓋率。我希望在他們所有的應用程序代碼中有100%的覆蓋率。一開始他們不喜歡這樣,但是到了期中,他們的測試的覆蓋率通常都達到100%。

    我已經為 TestNG,、djUnit、 Eclipse Test 和 Performance Tools Platform (TPTP) 安裝了插件程序。其中每一個都有一組特性支持有效的單元測試。關鍵是有大量合適的單元測試工具提供給每一個開發人員,因此缺少工具不再被認為是沒有創建單元測試的理由。

    測試帶有復雜的依賴性?使用模擬對象

    一個好的單元測試檢測一個獨立的方法。在一個設計良好的系統里,對象們協同工作共同完成一項任務;因此,為了檢驗一種方法,通常我們需要提供使得這種方法完成其任務的其他對象。企業應用程序里的對象相當復雜,很難創建,并且他們的狀態依賴外部的對象。一個數據庫相關的應用程序有許多這樣的對象,如連接、語句、結果集等等。我們想要單元測試簡單快速的執行。如果我們需要在每次單元測試前將數據庫重新設置到一個已知狀態,那么測試會相當復雜并且運行速度自然會比我們期望得要慢。

    簡化單元測試的一個流行技巧就是創建僅用于測試中的模擬對象。為了達到快速測試的目的,我們創建模擬對象來代替真實的對象。模擬對象被 Tim Mackinnon、 Steve Freeman 和 Philip Craig 1 所支持并成為單元測試工具箱的主要組成部分。一些書籍和論文講述了如何在單元測試中使用模擬對象,描述的是模擬對象應該具備的能力以及如何使用他們。盡管如此,在沒有任何基礎的情況下開始創建模擬對象是相當困難的。我們希望能夠自動完成這項任務。

    有一些軟件工具,像 EasyMock, 2 提供了自動幫助功能,但是它們可能很復雜而且也很難使用。此外,他們不是總能夠與我們其他的開發工具兼容。但是利用現有的工具可以有一些創建模擬對象或是相當能力的簡單方法。文章后面的部分將展示利用 Eclipse 平臺做到這一點的一些方法。

    從接口創建模擬對象

    面向對象的設計專家建議我們對接口進行編程。如果我們這樣做,設計會更加新穎、靈活并且對變化反應靈敏。我們來看這樣一個對接口編程例子,我們使用 Java JDBC™ API 來操作數據庫。我們將考慮基于 JDBC API Tutorial and Reference, Second Edition 一書中代碼的簡單例子。在關系數據庫中有一個表格,表格中有 a, b, c 三列,有整數型、字符串型和浮點型三種數據類型。下面的方法,在一個被稱為 DatabaseExample 的類中,使用數據庫 Connection 對象,從數據庫中讀取記錄并打印出數值。

    為了給 readABC( ) 編寫單元測試,我們需要一個 Connector 對象、一個 Statement 對象和一個 ResultSet 對象。Connector、 Statement 和 ResultSet 都是 java.sql 數據包中已設定的接口。特定的數據庫系統提供這些接口的具體實現。readABC( ) 方法不需要依賴任何特定的數據庫系統。我們的測試應該也不需要。事實上,我們可能也沒有選定的數據庫軟件。既然測試里的方法寫在接口中,我們可以為我們測試的每一個接口創建一個模擬對象。

      讓我們以被傳遞到方法之中的 Connection 對象為出發點。我們調用的唯一的 Connection 方法是 createStatement( )。但是我們的 Connection 必須完成定義在 Connection 接口中的所有方法。使用 Eclipse 創建這樣一個對象很簡單。我們按照以下步驟執行:

      在 Eclipse 中創建一個完成 Connection 接口的新類(稱它為 MockConection),檢查為繼承的抽象方法產生樁模塊的選項。Eclipse 為非 void 的方法產生帶有默認返回值的新類。如果返回值是一個對象,默認為空值。
      找到那些以測試里的方法命名的方法,并提供一個行為像真實對象那樣的實現。
      在模擬對象里添加方法,使得您的測試正確地初始化。

      為了實現我們的方法版本,我們需要一個對象來實現 Statement 接口。我們將按照上面的第一步創建一個默認值,稱作 MockStatement,F在我們可以執行經過簡單變換的方法:

    既然在 MockConnection 類里我們不需要任何其他東西,那么我們不需要編寫任何初始化代碼。當我們以后為其他測試(包括測試代碼,就像應用程序代碼)使用類的時候我們可能需要添加這些代碼。

      MockStatement 必須為執行對數據庫 SQL 查詢提供行為。這意味著它必須返回到一個 ResultSet 對象。ResultSet 對象需要提供測試中的方法所使用的行為。這在上面步驟中的第三步有所體現。因此,讓我們創建 MockResultSet 對象。

      在我們使用第一個步驟創建默認對象之后,我們需要為 next( )、getInt( )、getString( ) 和 getFloat( )方法提供一個實現。讓我們先從 next( )方法入手。Next( ) 只是將指針指向從查詢返回的下一行。這意味著在 MockResultSet 里我們需要一個 collection 來實現重復操作。我們可以通過在 MockResultSet 里創建一個私有 Collection 實例來實現,并提供對其進行訪問并在其中進行重復操作的方法。我們通過在類中添加下列代碼開始!  

    現在我們需要創建一個 MockResultSet 實例,為其裝上我們想要(期待)的從數據庫查詢返回的記錄,并連接使用 MockResultSet 對象的 MockStatement 對象。

    第一次測試,我們想確保我們可以返回記錄的結果。因此我們將創建一個 MockResultSet 對象,為其裝上記錄,將它傳遞給 MockStatement,并將這個 MockStatement 傳遞給 Connector。我們的測試實例代碼看上去像這樣:    

      首先,我們在 MockConnection 中增加一個 setStatement。這只是當調用 createStatement( ) 方法時在要返回的連接中節省一個 Statement (MockStatement)。當執行測試時,我們在 readABC( )方法中的 while 循環一開始處得到一個空指針異常。問題是在 MockStatement 中 executeQuery( )方法并不返回 MockResultSet。讓我們改變這一點!  

      無論我在模擬對象的什么地方改變樁模塊來執行適當的活動以支持我們測試,我都按照慣例加入了注釋"http:// MOCK",F在當我運行測試時,沒有成功,因為聲明期望我輸入的字符串并返回一個空的字符串(不是空值)。我們需要在 MockResultSet 中執行 next( )方法,然后執行從記錄中獲取數值的方法。next( ) 方法實施看上去像這樣:
           
      最后,我們執行缺少的 get...( )方法。下面的代碼顯示 getInt( )方法看上去如何。getString( ) 和 getFloat( )方法是相似的。

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/

    TAG: 單元測試


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>