張敏,陳靜,王娟
?
基于MVC模式的Web系統自動化單元測試方案
張敏,陳靜,王娟
摘 要:隨著網絡技術的不斷發展,Web應用的質量和可靠性變得越來越重要,如何對Web應用提出一套完整的測試方案保證Web應用的質量成為當前迫切需要解決的問題。針對基于MVC模式的Web應用系統,提出了一套全面的自動化單元測試方案,確定了一套實用的單元測試流程,并按照提出的方案和流程對系統進行測試,通過重構解決發現的問題,改善了系統的性能。
關鍵詞:單元測試;自動化;JUnit
隨著網絡技術的不斷成熟以及人們對網絡需求的多樣化發展,Web應用越來越普及并日益復雜,如何構建快速、安全、健壯的Web應用系統已經成為亟待解決的問題。
在快速開發Web應用時,測試作為軟件工程中極為重要的一個角色常被忽視。由于單純地認為測試工作耗費時間,商業效益不顯著,許多開發人員甚至企業摒棄了寶貴的軟件工程原則,在完成了項目的分析、設計、開發后才考慮開展測試工作。盡管開發人員在編碼過程中煞費苦心,代碼質量卻往往和預期相反,系統不穩定、不健壯,這些因素又減緩了開發過程,增加了開發成本。因此如何用高效率創造高質量的Web應用系統,保證系統的正確性和可靠性已經受到重視;Web測試作為Web應用系統開發過程中的一個重要環節,如何有效、系統地開展該項工作是保障系統可靠性的關鍵。
單元測試在Web測試中發揮著至關重要的作用,由于單元測試的對象是可獨立編譯或匯編的程序模塊,單元測試的目的是檢查每個軟件單元能否正確地實現設計說明中的功能、性能、接口和其他設計約束等要求,發現模塊內可能存在的各種差錯,因此及早地進行單元測試可以快速適應需求變化,避免產生大量錯誤,提高系統性能。針對目前常用的基于MVC模式的Web應用系統,本文提出了一套通用的自動化單元測試解決方案,并以該方案為指導,構建了針對Web應用系統的自動化單元測試系統,發現了系統在開發過程中存在的問題,通過對系統部分重要功能的重構有效地解決了問題,改善了系統性能。
單元測試包括程序邏輯性測試、集成測試、功能測試。總體測試方案從局部到整體展開,是一個典型的MVC交互的結構圖,如圖1所示:

圖1 整體結構圖
用戶可以通過MVC模式實現查詢、修改等交互操作。MVC模式分為3個模塊,分別是模型(Model)、控制器(Controller)、視圖(View),并通過模型模塊和數據庫模塊進行交互,因此測試方案相應地劃分為模型測試模塊,使用Junit對Java Bean進行測試;控制器測試模塊,使用Cactus和HttpUnit對Servlet進行測試;視圖測試模塊,使用HtmlUnit和JsUnit對Html,Jsp和JS進行測試;數據庫測試模塊,在對數據庫模塊進行測試時,常使用模擬連接、構造數據和驗證數據等方法。
在對每一模塊進行測試時,根據模塊中的源文件構造相對應的測試文件,通常為一對一的關系,即一個源文件對應一個測試文件,在一個測試文件中,按測試粒度由小到大的規則,首先進行程序邏輯性測試,粒度大小為一個函數,針對文件中每一個函數編寫對應測試函數;功能測試關注的是程序某一功能的實現是否正確,相對函數的測試粒度增大,因此在程序邏輯性測試之后進行;在集成測試時采用增量式方法,由若干函數增加至一個文件,由一個文件增加至若干文件,最終將所有的測試文件進行集成測試。增量式集成測試最好伴隨程序邏輯性測試和功能測試進行,通過不斷地集成測試,從總體上提高了測試的質量和效率。
因此,本文提出的測試思想和方案具有一定的通用性,測試的整體思路是首先由大到小劃分測試模塊為若干測試文件,最終劃分到函數粒度,在函數粒度級別完成邏輯性測試,覆蓋代碼及功能分支,再由小到大增量完成集成測試,覆蓋功能性測試。通過這樣的測試思想,使得系統由代碼分支到系統功能被充分測試,及早充分發現系統中存在的問題,提高開發效率,有效地降低開發和后期維護成本。
1.1 用JUnit實現單元測試
JUnit是由Erich Gamma和Kent Beck共同為編寫單元測試發布的框架,用于編寫和運行可重復的測試用例。它提供了豐富的斷言機制測試期望結果,可方便地組織和運行測試套件,在極限編程和重構實現中發揮著重要作用。在實際測試中,對每一個Class編寫對應的測試文件,Class中每一個方法對應一個測試函數。當Class的功能變動時,只需修改對應的測試函數,如果是對Class中的代碼進行重構,即改變代碼不改變功能,則不需修改測試文件的內容,通過不斷重構和執行測試用例來改善代碼質量。在編碼和測試的過程中,必須確保所有重要代碼都被測試,有多種測試覆蓋策略,例如按代碼行數覆蓋、按分支覆蓋等。
1.2 對數據庫進行測試
采用JUnit對數據庫進行測試時,檢查相關輸入數據,傳統且簡單的方法就是用if語句與期望值進行比較,在JUnit中,用斷言來代替大量的if語句。斷言是另一種將期望值與實際值比較的方式,如果比較的結果相等,則測試用例通過,否則失敗。在JUnit中,將初始的變量或者對象放在setUp()中,它是獨立于斷言的,因此同一個變量或者對象可以服務于多個測試用例;當測試結束,將銷毀變量或者對象放在tearDown()中實現。
在對數據庫進行測試時,首先驗證是否正確建立連接,該過程需要連接真實的數據庫完成;由于在真實環境中進行測試易產生錯誤、降低測試效率,因此最好模擬Connection、Statement、Resultset測試訪問語句是否正確,可以用工具EasyMock實現模擬過程;開發人員在編寫代碼對數據庫進行操作時,經常忘記釋放資源,而JDBC API不自動回收資源,會導致由資源泄漏引起的眾多問題,因此需要測試JDBC資源是否釋放。
數據庫測試最常見的方式是向表中插入一條記錄,然后進行驗證,最后刪除該條記錄。若多個測試共享同一個數據庫,在這種并發狀態下,數據庫處于變動之中,導致多個測試之間相互影響,可采用以下方法解決該問題:一是使用回滾技術,將從插入到刪除的過程作為一個整體,如果被中斷或出錯就進行回滾;二是在setUp()中實現數據庫連接和數據初始化,然后在測試函數中插入記錄并進行斷言,最后在teardown()中刪除記錄并釋放JDBC資源。
1.3 對服務器組件進行測試
Cactus是JUnit的擴展,可方便地實現對服務器端組件的測試,包括Servlet,EJB,Taglib,Filter等。Http Unit是一個集成測試工具,要有兩個功能,一是作為提供發送請求和接收響應功能的客戶端,通過模擬瀏覽器的行為與服務器端進行交互并處理返回的表格表單等;二是簡化了驗證響應內容的方法、簡化斷言。
在本文提出的方法中,采用Cactus與Http Unit相結合的方式對服務器進行測試,用Cactus實現模擬服務器操作過程,用Http Unit進行斷言可以精確定位表單返回值。在MVC模式中,基礎服務器組件是Servlet,常見測試方法是對Servlet的doGet()和doPost()方法進行測試,此外,還需對Request進行測試,驗證接收的值和預期的值是否相等。為了測試Servlet是否跳轉至正確的頁面,可通過抓取目標頁面的內容和預期的相比較來確定。
1.4 對視圖進行測試
View的測試包括驗證JSP頁面的正確性以及對JavaScript文件的測試。本文分別采用HtmlUnit和JsUnit完成。如同在瀏覽器中的操作一樣,HtmlUnit提供了一個接口允許調用網頁,填寫表單,點擊鏈接等。JsUnit是一個支持客戶端JavaScript腳本的單元測試框架,使用它對JavaScript編寫的函數進行行為測試。在驗證JSP頁面的正確性時需要查找空鏈接,本部分詳細介紹一種用HtmlUnit實現的算法(算法名稱:checkLink),可以有效地查找到存在的空鏈接,算法的關鍵步驟如下:
第一步:調用WebClient.getPage(URL root)進行頁面檢索,root為主頁地址,本系統中為典型案例的主頁地址。
第二步:如果該頁面是HtmlPage,將得到所有的<a>標記,并遞歸跟蹤每一個鏈接,使用HtmlAnchor中的click方法判斷鏈接是否有效,如果有效,將已檢查過且有效的鏈接添加至一個ArrayList中并繼續跟蹤,否則跳轉至第三步或第四步。
第三步:如果鏈接到一個域外的頁面,則終止該級的鏈接檢查,返回上一級頁面繼續。
第四步:當跟蹤某個鏈接出錯時,則判定該鏈接失效,將失效的鏈接添加到一個ArrayList中,終止該級的鏈接檢查,返回上一級繼續執行。
為了提高程序執行的效率,需要增加判斷方法,對已經檢查過的url地址和本頁中的鏈接即以“#”開頭的地址,不做重復性的檢查,否則就會產生循環遞歸的問題,最終導致資源耗盡。對不同參數但指向同一頁面的地址,采用“?”作為判定條件。
本文提出的單元測試方案適用于基于MVC模式的Web應用系統,并已有效地應用在實際系統的測試中,通過對一系列Web應用系統進行測試,發現系統中存在的問題并通過重構解決,提高代碼質量,使系統更加高效穩定運行。
2.1 Web系統存在的問題
在對實際系統進行單元測試的過程中,除了發現各系統實際存在的Bug外,還發現Web系統在開發過程中通常會出現的一些問題。這些問題雖然本身不是Bug,但它們的存在會帶來比Bug更嚴重的問題,多數Bug可以快速修復,使得系統功能恢復正常,但是在開發過程中,由于不良設計、不良開發習慣和水平低下的開發人員等原因導致的問題不僅嚴重影響系統的功能和性能,還使測試模塊難以編寫,影響測試效率,從而降低系統開發效率,提高開發和維護成本,降低系統可靠性?,F將開發過程中最容易出現的幾類問題歸納如下:
1)源文件中單個函數實現功能過多。這樣會導致測試不靈活,函數中的所有測試點只能同時進行,由于測試粒度大,不利于定位出錯地方,還會增加對環境的依賴。例如,一般在實現Servlet功能的初始階段,可能會把所有功能都放在一個函數中,隨著Servlet功能的增多,函數功能及函數代碼相應增多,這樣就導致單元測試函數功能復雜且單元測試代碼粒度過大、難于維護和定位錯誤、可讀性差等問題。在具體實現時,如果doPost()函數功能過多,代碼過長,不利于編寫測試用例,即使測出問題也難以確定錯誤模塊,降低開發效率。
因此,通過函數單元測試發現的問題可以總結出,在開發時,函數功能的設計及開發尤為重要,開發首要的原則就是功能獨立,函數粒度不宜過大,可以通過減少單個函數功能、提取公共代碼等方法實現。
2)源文件代碼冗余,包括變量冗余和函數冗余。這不僅使編碼容易出錯,修改不方便,同時也增加測試難度和測試量。例如,數據庫的連接和釋放的代碼多次出現在不同的方法中,或者實現對數據庫進行插入、刪除時,由于表名等名稱不同而導致冗余,在這種情況下,如果需要調試錯誤(如將沒有釋放的數據庫連接關閉),則會涉及到多個方法,漏改的情況容易出現。因此導致代碼可維護性和可讀性差,在開發階段如出現需求變更或者人員變更,則代碼的維護工作會變得異常復雜。
3)過于依賴框架。除了對數據庫的依賴之外,還存在對Web容器的緊密耦合。這樣的設計會使代碼邏輯不清晰,降低代碼質量,給閱讀、修改帶來困難,且無法進行模擬測試,導致測試只能在真實環境下進行,在測試過程中需要反復調用數據庫、Web服務器,浪費資源,且在大數據量的情況下,效率非常底下。
2.2 通過重構解決問題
針對在測試中發現的系統存在的問題,提出了以下解決方法,并通過重構完成。
1)明確函數的功能,拆分較大模塊函數成為大小適中的函數,粒度過大不利于測試,粒度過小會使得開發和測試過程變得繁瑣,增加開發和測試成本。例如在對Servlet重構時,本著極限編程及測試驅動開發的思想,應針對不同的功能編寫測試函數,將doPost()函數拆分成若干函數以實現不同功能,盡量保證各函數之間低耦合高內聚的特性,當所有測試用例通過時,每一個函數實現了預期的功能,在保障功能正確的同時提高了代碼質量。
2)針對程序中存在的大量冗余代碼,分析代碼功能,將相同功能的代碼通過重構抽取成公共方法封裝在類中,供其他程序調用。例如,可以寫一個數據庫操作類,對數據庫操作進行合理的封裝,避免數據庫操作的重復代碼,實現了代碼的重用性。
3)為減少對框架的依賴,業務邏輯盡量從容器中抽取出來,例如,針對業務邏輯依賴數據庫訪問層接口的問題,可以創建另一個類實現這個接口,實現與數據庫交互。通過業務邏輯與持久框架的分離,可以使用預定義的數據對業務邏輯測試。
按照高耦合、低內聚的原則,根據上述發現的問題及相應的解決方法,通過對系統中重要功能進行重構,減少了代碼冗余,改善了代碼質量,提高了系統性能和穩定性。
本文提出了一套單元測試方案,系統地建立了針對MVC模式的Web應用的測試流程,發現了開發中的問題,提出了有效的解決方法,并將測試方案以及重構思想有效地應用到實際系統中,探索了單元測試在測試驅動開發中的應用,總結了寶貴的經驗。本文的特點在于針對一類特定問題提煉出測試思想,形成了一套通用的測試方案,重點總結了測試技巧以及在測試中發現的問題,并通過不斷地重構,提高效率,對以后的開發和測試均有指導意義。
參考文獻
[1] Edward Hieatt,Robert Mee. Going Faster:Testing The
Web Application [J].IEEE SOFTWARE,2002,19(2):60-65
[2] Gamma E. and Beck K., "JUnit," http://junit.org, 2005.
[3] 徐雯,高建華. 基于Spring MVC及MyBatis的Web應用框架研究[J] 微型電腦應用,2012.7
[4] EasyMock home page. http://www.easymock.org.
[5] Louridas.P JUnit: Unit Testing and Coding in Tandem [J].IEEE SOFTWARE,2005,22(4):12-15
[6] 申華.基于MVC的光照度智能控制監測平臺研發[J]信息與電腦,2015.12
[7] 周立力,極限編程的質量保證分析[J]. 計算機應用與軟件,2010,27(4):167-168
[8] S Freeman,《測試驅動的面向對象軟件開發》[M] 北京:電子工業出版社,2010
Automated Unit Testing Solution of Web System Based on MVC
Zhang Min, Chen Jing, Wang Juan
(Xi'an FANYI University, Xi’an 710105, China)
Abstract:With the development of network technology, the quality and reliability of Web application was more and more important. How to make a complete testing solution for Web applications to ensure the quality was an urgent problem which needs to solve. The article gave a comprehensive automated testing solution for Web application system based on MVC. It made a simple and practical testing process, and did testing for web systems according to the proposed solution and procedure. It could not only find system error, but also summarize problems found in system developing period. And it could solve problems according to reconstruct in order to improve system performance.
Key words:Unit Testing; Automation; JUnit
收稿日期:(2015.12.03)
作者簡介:張 敏(1980-),女,赤峰市,西安翻譯學院,講師,碩士,研究方向:數據庫與知識庫,西安,710105 陳 靜(1986-),女,西安翻譯學院,助教,碩士,研究方向:信息處理,西安,710105
文章編號:1007-757X(2016)02-0078-03
中圖分類號:TP311
文獻標志碼:A