陳麗萍 張 勇 丁智敏
(巢湖學(xué)院計算機與信息工程學(xué)院,安徽 巢湖 238000)
單元測試是極限編程的基礎(chǔ)[1,2],單元測試的目的是保證每個程序模塊能夠正確運行。然而在實施單元測試驅(qū)動開發(fā)過程中,往往和被測模塊交互的系統(tǒng)內(nèi)某個模塊或系統(tǒng)外實體尚未開發(fā)出來,此時可借助Mock Objects技術(shù)[3]。它從測試中分離了外部不需要的因素并且?guī)椭_發(fā)人員專注于被測試的功能[4]。EasyMock框架[5]是Mock Objects技術(shù)的實現(xiàn)框架。它通過使用動態(tài)代理提供對接口和類創(chuàng)建Mock對象,并利用Mock對象模擬協(xié)同模塊,從而使單元測試順利進行。在開發(fā)時,將EasyMock、Junit集成到IDE中可方便的完成自動化測試[6]。本文在總結(jié)EasyMock框架的特點基礎(chǔ)上,介紹了基本測試框架和分析了功能優(yōu)缺點,并且針對缺點給出了相應(yīng)的解決方案。
圖1 EasyMock功能類
EasyMock[7]擁有很多的API函數(shù),可以直接用在測試程序中,其主要的功能類結(jié)構(gòu)如圖1所示:
EasyMock框架中與用戶聯(lián)系最緊密的類EasyMock類,該類提供了create,replay和verify mock對象等靜態(tài)方法以及一系列的標準的參數(shù)匹配器。
IMocksControl主要用于創(chuàng)建Mock對象,并負責(zé)管理Mock對象。
IExpectionSetters接口主要是對Mock對象期望調(diào)用的方法進行一些相關(guān)的設(shè)置。
MocksControl類主要提供了用于添加Mock對象的預(yù)期行為和實際調(diào)用的方法。
通過EasyMock創(chuàng)建Mock對象,并應(yīng)用Mock對象來模擬外部協(xié)同模塊,完成單元測試,需經(jīng)歷五個步驟。如圖2所示:
圖2 EasyMock應(yīng)用步驟
首先創(chuàng)建被模擬模塊的Mock對象,這里可以通過兩種方式來完成。一種是使用EasyMock的creatMock方法直接創(chuàng)建;另一種是通過Easy-Mock類的createControl方法,先創(chuàng)建IMockControl對象,進而創(chuàng)建Mock對象。
接下來錄制Mock對象的預(yù)期行為即為創(chuàng)建的Mock對象設(shè)定預(yù)期的方法調(diào)用和方法調(diào)用所產(chǎn)生的輸出。
接著在使用Mock對象進行實際的測試前,需要將Mock對象的狀態(tài)切換為replay狀態(tài)。設(shè)置Mock對象為replay狀態(tài)可以使用replay方法。
之后是執(zhí)行需要測試的業(yè)務(wù)代碼并檢查代碼是否返回正確的結(jié)果。
最后是驗證。它來驗證整個過程中,Mock對象是否真正完成了record階段的設(shè)定。
Easymock通過檢查附加給測試響應(yīng)的斷言來驗證測試的結(jié)果和交互行為是通過還是失敗,有大量的Junit的斷言可供選擇。軟件結(jié)構(gòu)的設(shè)計會導(dǎo)致Easymock框架的使用情況。具體優(yōu)缺點分析如下:
4.1.1 EasyMock的優(yōu)點
(1)EasyMock提供了動態(tài)構(gòu)建Mock對象的方法,而無需開發(fā)人員額外實現(xiàn)Mock對象的代碼,很大程度上減少了工作量。
(2)EasyMock可以完成多種Mock對象的測試場景。例如:當(dāng)真實協(xié)同對象實際還不存在(如需要和其他開發(fā)人員開發(fā)的模塊交互);當(dāng)真實協(xié)同對象行為難于觸發(fā)(如根據(jù)需要制造網(wǎng)絡(luò)故障)等。
4.1.2 EasyMock的缺點
(1)EasyMock通過創(chuàng)建Proxy的方式來實現(xiàn)的Mock對象。因而Mock對象不能訪問靜態(tài)方法,這就造成EasyMock不能模擬靜態(tài)方法。
(2)EasyMock通過創(chuàng)建Proxy的方式來實現(xiàn)的Mock對象,同時Java的封裝特性,使得Mock對象不能訪問私有方法和final方法。這就造成EasyMock不能模擬私有方法和final方法。
(3)EasyMock 不能對 Object類的 equals(),hasCode()、toString()方法模擬。 也就是說,Easy-Mock對這幾種方法模擬時,無法改變其行為,它們?nèi)耘f按照默認的方式執(zhí)行。此問題還有待于進一步的研究和分析。
EasyMock不能模擬靜態(tài)方法。為了克服該缺點,這里可以通過整合EasyMock和PowerMock。PowerMock使用CGLib來操縱字節(jié)碼來實現(xiàn)靜態(tài)方法的Mock對象,因此可以對靜態(tài)方法模擬支持[8]。因此在Mock方法時,使用EasyMock模擬普通方法,用PowerMock去模擬靜態(tài)方法。Easy-Mock和PowerMock的結(jié)合可以更好地實現(xiàn)測試。
EasyMock不能模擬私有方法和final方法。為了解決該問題,可以通過使用字節(jié)碼技術(shù)修改class文件中字節(jié)碼的關(guān)鍵詞,將私有方法變?yōu)楣蟹椒ê蚮inal修飾符去掉。在這里借助Java的字節(jié)碼操作工具javassist,因為javassist可以在不需要了解虛擬機指令前提下,使用java編碼形式動態(tài)對類轉(zhuǎn)換、修改class中的方法。這樣可以將含有final或private修飾符的類在被當(dāng)前JVM加載前對此類修改。這樣去除final和private標識符后,進而使用EasyMock進行測試。
5.1.1 示例程序 1
使用EasyMock框架對一個應(yīng)用程序測試。這里的應(yīng)用程序結(jié)構(gòu)設(shè)計如圖3所示:
圖3 結(jié)構(gòu)設(shè)計(1)
這里待測試類為Calculator,Calculator類中add方法完成兩個整數(shù)之和,而add方法使用了Math類的addInteger方法。Calculator類和Math類對應(yīng)代碼如下:
5.1.2 示例程序 2
使用框架對另一個應(yīng)用程序測試。這里的應(yīng)用程序結(jié)構(gòu)設(shè)計如圖4所示:
圖4 結(jié)構(gòu)設(shè)計(2)
這里待測試類為Calculator,Calculator類中add方法完成兩個整數(shù)之和,而add方法使用了Math類的addInteger方法。Calculator類和Math類對應(yīng)代碼如下:
這里測試平臺為 Eclipse-sdk-3.3, 使用JUint4.10 和 EasyMock3.2。將 EasyMock 框架與注入解決方案后的EasyMock框架分別對示例程序1,2進行測試。
使用EasyMock框架和注入解決方案后的EasyMock框架對示例程序1測試,測試結(jié)果分別如圖5的(a),(b)所示:
圖5 對示例程序1測試結(jié)果
使用EasyMock框架和注入解決方案后的EasyMock框架對示例程序2測試,測試結(jié)果分別如圖6 的(a),(b)所示:
圖6 對示例程序2測試結(jié)果
由此可見,EasyMock框架在模擬對象時有一些限制:不能對靜態(tài)方法、私有方法和final方法模擬,導(dǎo)致測試失敗。而使用了注入解決方案后的EasyMock框架可以應(yīng)用于更多的測試情況,應(yīng)用范圍更廣。
由于IT界對測試驅(qū)動開發(fā)技術(shù)的持續(xù)關(guān)注與偏愛,軟件單元測試也成為人們研究的熱點,EasyMock是單元測試的Mock工具之一。本文研究了EasyMock測試框架和應(yīng)用;關(guān)注該工具在實際測試中的可行性,并且根據(jù)實際的需要采用整合Powermock框架和利用字節(jié)碼操作工具javassist對類文件的修改來減少EasyMock框架的Mock對象的限制,測試結(jié)果證明了更好地滿足實際的需要。
[1]Erickson J,Lyytinen K,Siau K.Agile Modeling,Agile Software Development,and Extreme Programming:The State of Research[J].Journal of Database Management,2005,(4):88-100.
[2]Mordinyi R,Kuhn E,Schatten A,Towards an Architectural Framework for Agile Software Development[C]//International Conference and Workshops on Engineering of Computer Based Systems.American,2010:276-280.
[3]Mackinnon T,Freeman S,Craig P.Endo-Testing:Unit Testing with Mock Objects[C]//Proceeding of the eXtreme Programming and Flexible .Italy,2000:21-23.
[4]Jafadeesh Nandigam,Tao Yonglei.Using mock object frameworks to teach object-oriented design principles[J].Journal of Computing Sciences in Colleges,2010,(1):40-48.
[5]Tammo,F(xiàn)reese.EasyMock:Dynamic Mock Objects for Junit[C]//Proceedings of the 3rd International Conference on Extreme Programming and Agile Processes in Software Engineering.Italy,2002:1-5
[6]Petar Tahchiev,Felipe Leme,Vincent Massol,et al.Junit實戰(zhàn)[M].王魁,譯.北京:人民郵電出版社,2012:96-129.
[7]EasyMock 官方網(wǎng)站[EB/OL].(2013-7-11)[2014-1-29]http://www.easymock.org/.
[8]PowerMock 官方網(wǎng)站.[EB/OL].(2013-11-19)[2014-1-29]http://www.Powermock.org/.