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

下載本文檔

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

文檔簡(jiǎn)介

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

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

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

4、2.EasyMock使用示例EasyMock的使用方法和原理的詳細(xì)說明請(qǐng)參見EasyMock使用方法和原理剖析一文。在這里,我們僅以HttpServletRequest為例對(duì)EasyMock的功能做簡(jiǎn)單說明。在部署到Servlet容器之前,需要和HttpServletRequest進(jìn)行交互的模塊可以通過構(gòu)建Mock對(duì)象的方式進(jìn)行單元測(cè)試。下面是使用EasyMock(version 2.3)構(gòu)建Mock對(duì)象進(jìn)行簡(jiǎn)單測(cè)試的例子: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對(duì)象mockRequest。當(dāng)Mock對(duì)象創(chuàng)建好以后,我們就可以對(duì)Mock對(duì)象的預(yù)期行為和輸出進(jìn)行設(shè)定。對(duì)預(yù)期行為和輸出的設(shè)定分成兩個(gè)部分:(1)對(duì)指定方法進(jìn)行調(diào)用;(2)對(duì)預(yù)期輸出進(jìn)行設(shè)定。在上例中,mockRequest.getHeader(Host);對(duì)Mock對(duì)象的getHeader方法進(jìn)行了調(diào)用,之后用expectLastCa

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

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

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

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

11、們可以給出Mock對(duì)象配置文件的模板:?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對(duì)象的生成信息,mockBehaviors部分將配置Mock對(duì)象的預(yù)期行為和輸出。印花稅會(huì)計(jì)分錄接下來,我們將對(duì)這兩部分進(jìn)行詳細(xì)的說明。根據(jù)配置文件生成Mock對(duì)象配置文件中所包含的Mock對(duì)象生成信息包含在mockObject元素

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

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

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

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

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

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

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

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

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

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

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

24、k對(duì)象,它的預(yù)期輸出,就是被測(cè)試對(duì)象在正確運(yùn)行情況下的預(yù)期輸出。通過這種方式,我們就可以用類似配置Mock對(duì)象的方式對(duì)預(yù)期結(jié)果進(jìn)行配置了。在XMLEasyMock中我們提供了一個(gè)測(cè)試用的接口SalesOrder,它的實(shí)現(xiàn)類SalesOrderImpl的主要功能是從數(shù)據(jù)庫(kù)中讀取一個(gè)Sales Order的Region和Total Price,并根據(jù)讀取的數(shù)據(jù)計(jì)算該Sales Order的Price Level:如果我們對(duì)getPriceLevel方法進(jìn)行測(cè)試,就可以將該方法在正確運(yùn)行下的預(yù)期輸出抽象成Mock對(duì)象,并配置如下: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.使用配置文件運(yùn)行測(cè)試用例與在代碼中動(dòng)態(tài)構(gòu)建Mock對(duì)象不同,XMLEasyMock是在配置文件的解析過程中動(dòng)態(tài)生成Mock對(duì)象的。因此,如果用戶需要使用Mock對(duì)象,需要從解析模塊中獲取。XMLEasyMock提供了一個(gè)工具類EasyMockUtil,這個(gè)工具類提供了findMockObjectByName方法用于返回Mock對(duì)象。該方法的輸入?yún)?shù)就是在配置文件的mockObject元素中配置的name屬性。另外,我們?cè)谏衔闹刑岬?,EasyMockUtil提供了方法loadConfig用于裝入配置文件,該方法的輸

27、入?yún)?shù)就是配置文件的路徑。在XMLEasyMock提供的測(cè)試代碼(SalesOrderTestCase.java)中,我們對(duì)ResultSet接口進(jìn)行了模擬,從而對(duì)SalesOrder的getPriceLevel進(jìn)行測(cè)試。在完成相關(guān)Mock對(duì)象的配置之后,我們可以通過XMLEasyMock提供的功能對(duì)測(cè)試用例實(shí)現(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等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論