Mock對象創(chuàng)建高效、靈活的測試用例_第1頁
Mock對象創(chuàng)建高效、靈活的測試用例_第2頁
Mock對象創(chuàng)建高效、靈活的測試用例_第3頁
Mock對象創(chuàng)建高效、靈活的測試用例_第4頁
Mock對象創(chuàng)建高效、靈活的測試用例_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、Mock 對象 創(chuàng)建高效、靈活的測試用例使用配置文件定義Mock對象,創(chuàng)建高效、靈活的測試用例私塾2011-01-19 10:35:15閱讀5評論0字號:大中小訂閱簡介:本文主要討論如何利用配置文件對Mock對象以及它的行為進行描述,從而分離測試數(shù)據(jù)和代碼,創(chuàng)建高效、靈活的測試用例。同時,本文給出了一套基于開源項目EasyMock的實現(xiàn),并通過一個示例來說明如何利用這一實現(xiàn)編寫測試用例。使用Mock方法能夠模擬協(xié)同模塊或領(lǐng)域?qū)ο?,從而把測試與測試邊界以外的對象隔離開。使單元測試順利進行。然而,Mock方法在輔助測試的同時,也給開發(fā)或測試人員帶來額外的編碼工作。另外,由于Mock對象本身并不能對

2、測試數(shù)據(jù)進行管理,因此測試數(shù)據(jù)的變動和Mock對象本身的變動,可能就會極大的增加編譯和部署的時間。本文提出一種利用XML文件對Mock對象進行配置的機制,并在開源項目EasyMock的基礎(chǔ)上實現(xiàn)了這種機制。實際上,讀者可以基于任何的自己熟悉的xMock項目來實現(xiàn)這里的思想。1.Mock對象的創(chuàng)建方法開發(fā)和測試人員在利用Mock方法進行單元測試時發(fā)現(xiàn),編寫自定義Mock對象會帶來大量額外的編碼工作:假如為測試中用到的每一個協(xié)同模塊或領(lǐng)域?qū)ο笫謩泳帉慚ock對象,最終的結(jié)果將是Mock對象的數(shù)目隨著系統(tǒng)中實際對象數(shù)目的增長而增長。2011個稅起征點此外,這些為創(chuàng)建Mock對象而編寫的代碼也很有可能

3、引入錯誤。目前,由許多開源項目對動態(tài)構(gòu)建Mock對象提供了支持,這些項目能夠根據(jù)現(xiàn)有的接口或類動態(tài)生成Mock對象,從而避免了編寫自定義的Mock對象,這樣不僅能減少一定的編碼工作,也可以降低錯誤引入的可能。EasyMock就是這些開源框架中的一個,它是一套通過簡單的方法對于給定的接口生成Mock對象的類庫。它提供對接口的模擬,能夠通過錄制、回放、檢查三個步驟來完成大體的測試過程。EasyMock可以驗證方法的調(diào)用種類、次數(shù)和順序,可以令Mock對象返回指定的值或拋出指定異常。通過EasyMock,開發(fā)或測試人員能夠比較方便的創(chuàng)建Mock對象,在一定程度上減少了創(chuàng)建Mock對象所帶來的工作量。

4、2.EasyMock使用示例EasyMock的使用方法和原理的詳細說明請參見EasyMock使用方法和原理剖析一文。在這里,我們僅以HttpServletRequest為例對EasyMock的功能做簡單說明。在部署到Servlet容器之前,需要和HttpServletRequest進行交互的模塊可以通過構(gòu)建Mock對象的方式進行單元測試。下面是使用EasyMock(version 2.3)構(gòu)建Mock對象進行簡單測試的例子:public class HttpServletRequestUtilpublic static boolean validate(HttpServletRequest r

5、equest)String host=request.getHeader(Host);return host.startsWith();public class HttpServletRequestTestCase extends TestCasepublic void testHttpSevletRequest()HttpServletRequest mockRequest=createMock(HttpServletRequest.class);mockRequest.getHeader(Host);expectLastCall().andReturn(:80).times(1);repl

6、ay(mockRequest);assertTrue(HttpServletRequestUtil.validate(mockReq uest);verify(mockRequest);首先,我們通過EasyMock提供的靜態(tài)方法createMock創(chuàng)建Mock對象mockRequest。當Mock對象創(chuàng)建好以后,我們就可以對Mock對象的預(yù)期行為和輸出進行設(shè)定。對預(yù)期行為和輸出的設(shè)定分成兩個部分:(1)對指定方法進行調(diào)用;(2)對預(yù)期輸出進行設(shè)定。在上例中,mockRequest.getHeader(Host);對Mock對象的getHeader方法進行了調(diào)用,之后用expectLastCa

7、ll().andReturn(:80).times(1)對Mock對象的預(yù)期輸出進行了設(shè)定。andReturn方法設(shè)定了當getHeader方法被調(diào)用時,將返回字符串:80,times方法設(shè)定了該方法預(yù)期被調(diào)用的次數(shù)是1。在結(jié)束對Mock對象預(yù)期行為和方法的設(shè)定之后,我們可以調(diào)用replay靜態(tài)方法將mockRequest對象切換成回放狀態(tài)。在回放狀態(tài)下,Mock對象的方法調(diào)用將返回預(yù)先設(shè)定的輸出。在上例中,HttpServletRequestUtil類的validate方法對mockRequest的getHeader方法進行了調(diào)用,并對得到的值進行驗證。最后,我們可以用verify方法來驗證

8、預(yù)期方法的調(diào)用是否真的完成了。假如將上例中expectLastCall().andReturn(:80).times(1)設(shè)定的調(diào)用次數(shù)修改為2,而實際測試中只調(diào)用了一次該方法,您將會看到以下的錯誤:通過示例,我們了解了EasyMock的使用方法。EasyMock能為單元測試提供了一定的便利,然而,它也有一些明顯的不足之處:測試數(shù)據(jù)和預(yù)期結(jié)果以編碼的形式寫在測試用例中,測試數(shù)據(jù)的任何微小變化都會導致代碼的重新編譯和部署;被測試模塊所包含的方法和參數(shù)硬編碼在測試代碼中,方法或參數(shù)的變化將導致所有相關(guān)測試代碼的修改(例如HttpServletRequest中的參數(shù)經(jīng)常會在開發(fā)過程中發(fā)生改變,這會影

9、響大量測試代碼);單元測試的測試過程包含在測試代碼中,當測試用例發(fā)生變化,測試代碼有可能需要全部重寫,造成代碼的頻繁修改和引入錯誤的機會。3.利用XML文件配置Mock對象為了改進目前EasyMock使用方法中存在的不足,我們需要引入配置文件來對Mock對象進行定義。我們的目標是通過配置文件的使用來實現(xiàn)測試代碼和數(shù)據(jù)的分離。當開發(fā)人員由于測試用例的變化而需要改變Mock對象的測試行為時,就可以直接對配置文件作出改動,而無需修改測試代碼。構(gòu)建Mock對象需要以下兩方面的信息:(1)Mock對象對應(yīng)的接口或類信息;(2)Mock對象的預(yù)期行為與輸出。如果將以上兩類信息配置在文件中,通過對配置文件的

10、解析來構(gòu)造Mock對象,就可以實現(xiàn)測試代碼和數(shù)據(jù)分離的目標,從而改進現(xiàn)有Mock對象構(gòu)造方法中的不足。本文在提出使用配置文件定義Mock對象這一機制的同時,也提供了一個基于EasyMock的實現(xiàn)。我們將這一實現(xiàn)稱為XMLEasyMock。XMLEasyMock的完整實現(xiàn)和相關(guān)的測試代碼都可以在xmleasymock.zip中找到。如果您使用Eclipse作為IDE,那么您可以將它導入您的Workspace(如下圖):在XMLEasyMock中,我們選用XML文件作為Mock對象的配置文件,XML文件的自定義和結(jié)構(gòu)特性使得它成為描述Mock對象最佳的選擇。根據(jù)以上對Mock對象信息配置的分析,我

11、們可以給出Mock對象配置文件的模板:?xml version=1.0encoding=UTF-8?mockConfig mockObjects mockObject name=Object namemockedClass=Mock class or interface/./mockObjects mockBehaviors mockBehavior mockObject=Object namemethod=Expected invocation methodparamValues paramValue type=Parameter typevalue=Parameter value/para

12、mValues ctrlOptions ctrlOption option=Control optionvalue=Expected return valuetimes=Expected invocation times/ctrlOptions/mockBehavior./mockBehaviors/mockConfig其中,mockObjects部分將配置Mock對象的生成信息,mockBehaviors部分將配置Mock對象的預(yù)期行為和輸出。印花稅會計分錄接下來,我們將對這兩部分進行詳細的說明。根據(jù)配置文件生成Mock對象配置文件中所包含的Mock對象生成信息包含在mockObject元素

13、當中。mockObject元素包含兩個屬性name和mockedClass,分別對應(yīng)Mock對象的名稱和對應(yīng)的接口或類。Mock對象的名稱用于和配置文件中的其它部分相關(guān)聯(lián),而對應(yīng)的接口和類用于Mock對象的生成。ResultSet接口是每個Java開發(fā)人員都非常熟悉的接口。以java.sql.ResultSet接口為例,為其生成一個Mock對象mockResultSet,可以在文件中配置為:mockObject name=mockResultSetmockedClass=java.sql.ResultSet/我們可以設(shè)想一下,在EasyMock中,如果我們需要創(chuàng)建ResultSet接口的一個M

14、ock對象,這個過程應(yīng)當是:IMocksControl mocksControl=EasyMock.createControl();ResultSet mockResultSet=control.createMock(ResultSet.class);其中,IMocksControl接口的實例mocksControl能生成并管理多個Mock對象。在XMLEasyMock中,我們?yōu)槊總€Mock對象創(chuàng)建一個MockObject類的對象,同時用一個MockObjectController對象來管理這些Mock對象。MockObjectController類擁有一個IMocksControl成員變量,

15、同時提供了replay、個人所得稅計算器verify和reset方法,供外部調(diào)用(如下圖):EasyMockUtil是提供給外部程序調(diào)用的工具類,loadConfig方法用于讀取配置文件,findMockObjectByName方法可以通過Mock對象的變量名返回Mock對象。配置Mock對象的預(yù)期行為接下來我們需要配置的是Mock對象的預(yù)期行為。Mock對象的預(yù)期行為可以簡單的理解為是Mock對象方法的調(diào)用以及該方法的預(yù)期輸出。我們需要在文件中分別配置方法的預(yù)期調(diào)用和預(yù)期輸出。Mock對象的預(yù)期方法調(diào)用配置在mockBehavior元素中。每個mockBehavior元素都包含兩個屬性:mo

16、ckObject和method屬性。mockObject指定該行為對應(yīng)的Mock對象的名稱(Mock對象必須在mockObject中定義過),method屬性則指定Mock對象中預(yù)期調(diào)用的方法。mockBehavior的子元素paramValues包含了需要配置的方法所對應(yīng)的參數(shù)列表。paramValues的每個子元素paramValue都包含兩個屬性:type和value,分別指定了參數(shù)類型和參數(shù)值。我們以ResultSet接口的Mock對象mockResultSet為例,如果我們期望對getString方法進行調(diào)用,可以配置以下信息:在對Mock對象的方法調(diào)用進行配置以后,我們接下來對方法

17、的預(yù)期輸出進行配置。方法的預(yù)期輸出定義包含在ctrlOptions中。ctrlOption中的option屬性指定了MockControl對象在指定方法返回值時選用的選項。Option屬性可選的值包括:其中,andReturn選項用于設(shè)定方法的預(yù)期返回值,當option屬性為andReturn時,我們可以在value屬性中配置方法的返回值。在預(yù)期方法確定以后,其返回值類型也確定了,因此我們無需在此指定返回值類型。times屬性用于指定預(yù)定方法的調(diào)用次數(shù)。如果希望為Mock對象方法設(shè)置默認的預(yù)期返回值,那么你可以選擇andStubReturn,這時value屬性中的返回值將作為預(yù)期方法的固定返回

18、值,而無需多次設(shè)定。andThrow選項用于設(shè)定預(yù)期異常拋出。當option屬性為andThrow時,value屬性用于指定預(yù)期的異常類型。times屬性同樣用于設(shè)定預(yù)期異常拋出的次數(shù)。如果希望為Mock對象方法設(shè)定默認的異常拋出,您可以相應(yīng)的選擇andSubThrow。如果預(yù)期方法的返回值為空(void),那么您應(yīng)當指定andVoidCallable方法。這時value屬性不用設(shè)定(如果設(shè)定,XMLEasyMock會忽略該屬性)。我們?nèi)匀挥肦esultSet接口的getString方法為例,說明預(yù)期輸出的配置效果:以上的配置相當于在EasyMock中調(diào)用:expectLastCall().a

19、ndReturn(My return value).times(1);expectLastCall().andThrow(new SQLException().times(2);XMLEasyMock中為每個Mock對象的預(yù)期行為創(chuàng)建一個MockBehavior對象。MockBehavior類中包含了兩個列表,分別包含了多個ParamValue對象和CtrlOption對象。所有MockBehavior對象都由MockBehaviorController統(tǒng)一管理。MockBehaviorController提供了loadMockBehaviors和runMockBehaviors方法,分別用于

20、讀入MockBehavior和執(zhí)行預(yù)期行為設(shè)定。這些類的關(guān)系如下圖所示:XMLEasyMock對Mock對象預(yù)期方法是通過類反射機制進行調(diào)用的。如圖4所示,當MockBehavior的runMockMethod方法被調(diào)用時,它首先通過Mock對象名查詢Mock對象,接著從ParamValue中取出用戶設(shè)定的參數(shù)類型和參數(shù)值。根據(jù)Mock對象的類型、Mock對象的方法名和參數(shù)類型列表,我們可以通過Class的getDeclaredMethod獲取到對應(yīng)的Method對象。最后,runModkMethod方法調(diào)用Method對象的invoke方法,完成Mock對象預(yù)期方法的調(diào)用。在對預(yù)期方法進行調(diào)

21、用之后,我們需要通過EasyMock類對方法的預(yù)期輸出進行設(shè)定。我們以設(shè)定預(yù)期返回值為例進行說明(設(shè)定預(yù)期異常拋出與此類似)。如圖5所示,MockBehavior類提供了runCtrlOptions用于設(shè)定方法的預(yù)期輸出。runCtrlOption方法首先調(diào)用之前得到的Method對象的getReturnType方法,獲取方法的返回值類型,并將該返回值類型作為參數(shù)傳遞給CtrlOption的runCtrlOption方法。runCtrlOption方法首先調(diào)用EasyMock類的expectLastCall靜態(tài)方法,獲得Mock對象所對應(yīng)的IMocksControl實例,之后,根據(jù)預(yù)期方法的返

22、回值類型對配置文件中的返回值進行格式化,將格式化后的數(shù)據(jù)作為參數(shù)傳遞給IMocksControl的andReturn方法,最后,調(diào)用times方法設(shè)定預(yù)期調(diào)用次數(shù)。以上是XMLEasyMock對Mock對象生成、Mock對象預(yù)期行為設(shè)定的具體實現(xiàn)。對于外部程序而言,只需要調(diào)用EasyMockUtil提供的loadConfig靜態(tài)方法就可以達到根據(jù)配置文件構(gòu)建Mock對象的目的了:EasyMockUtil的loadConfig方法MockObjectController的loadMockObjects方法和MockBehaviorController的loadMockBehaviors方法讀取和

23、創(chuàng)建Mock對象及其預(yù)期行為。MockBehaviorController的runMockBehaviors先后調(diào)用runMockMethod和runCtrlOptions方法設(shè)定Mock對象的預(yù)期方法調(diào)用和預(yù)期輸出。最后,loadConfig方法調(diào)用MockObjectControllerreplay方法將Mock對象切換成Replay狀態(tài)。4.利用Mock對象定義機制配置預(yù)期結(jié)果在進行單元測試時,被測試模塊的預(yù)期結(jié)果也編碼在代碼中,當測試數(shù)據(jù)或是測試用例發(fā)生變化時,預(yù)期結(jié)果也將發(fā)生改變。我們是否能將預(yù)期結(jié)果也定義在配置文件中呢?我們可以將被測試的對象在正確運行的情況下的行為抽象為一個Moc

24、k對象,它的預(yù)期輸出,就是被測試對象在正確運行情況下的預(yù)期輸出。通過這種方式,我們就可以用類似配置Mock對象的方式對預(yù)期結(jié)果進行配置了。在XMLEasyMock中我們提供了一個測試用的接口SalesOrder,它的實現(xiàn)類SalesOrderImpl的主要功能是從數(shù)據(jù)庫中讀取一個Sales Order的Region和Total Price,并根據(jù)讀取的數(shù)據(jù)計算該Sales Order的Price Level:如果我們對getPriceLevel方法進行測試,就可以將該方法在正確運行下的預(yù)期輸出抽象成Mock對象,并配置如下:mockConfig mockObjects mockObject n

25、ame=mockSalesOrdermockedClass=xmleasymock.demo.test.SalesOrder/mockObjects mockBehaviors mockBehavior mockObject=mockSalesOrdermethod=getPriceLevelparamValues/ctrlOptions ctrlOption option=andReturnvalue=expected result 1times=1/ctrlOption option=andReturnvalue=expected result 2times=1/./ctrlOptions

26、/mockBehavior/mockBehaviors/mockConfig 5.使用配置文件運行測試用例與在代碼中動態(tài)構(gòu)建Mock對象不同,XMLEasyMock是在配置文件的解析過程中動態(tài)生成Mock對象的。因此,如果用戶需要使用Mock對象,需要從解析模塊中獲取。XMLEasyMock提供了一個工具類EasyMockUtil,這個工具類提供了findMockObjectByName方法用于返回Mock對象。該方法的輸入?yún)?shù)就是在配置文件的mockObject元素中配置的name屬性。另外,我們在上文中提到,EasyMockUtil提供了方法loadConfig用于裝入配置文件,該方法的輸

27、入?yún)?shù)就是配置文件的路徑。在XMLEasyMock提供的測試代碼(SalesOrderTestCase.java)中,我們對ResultSet接口進行了模擬,從而對SalesOrder的getPriceLevel進行測試。在完成相關(guān)Mock對象的配置之后,我們可以通過XMLEasyMock提供的功能對測試用例實現(xiàn)如下:public class SalesOrderTestCase extends TestCasepublic void testAfterConfig()tryEasyMockUtil.loadConfig(/xmleasymock/demo/propert ies/mockConfig.xml);DBUtility mockDBUtility=(DBUtility)EasyMockUtil.findMockObjectByName(mockDBUtility);Connection conn=mockDBUtility.getConnection();Statement stmt=conn.createStatement();ResultSet rs=stmt.executeQuery(select*from sales_ord

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論