單元測(cè)試系列講座(1)_Junit+Easymock_第1頁(yè)
單元測(cè)試系列講座(1)_Junit+Easymock_第2頁(yè)
單元測(cè)試系列講座(1)_Junit+Easymock_第3頁(yè)
單元測(cè)試系列講座(1)_Junit+Easymock_第4頁(yè)
單元測(cè)試系列講座(1)_Junit+Easymock_第5頁(yè)
已閱讀5頁(yè),還剩30頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、1 Junit+Easymock drawed out by hongliang.chen2內(nèi)容提要內(nèi)容提要l 單元測(cè)試簡(jiǎn)介l 單元測(cè)試的好處l Mock 對(duì)象與 EasyMock 簡(jiǎn)介 l 使用 EasyMock 進(jìn)行單元測(cè)試 l 本次講座小結(jié)。3單元測(cè)試簡(jiǎn)介單元測(cè)試簡(jiǎn)介 單元測(cè)試是一個(gè)獨(dú)立的工作單元,是對(duì)應(yīng)用中的某一個(gè)模塊(module)的功能進(jìn)行驗(yàn)證。 在JAVA應(yīng)用程序中“獨(dú)立的一個(gè)單元”常指一個(gè)方法。一個(gè)工作單元是一項(xiàng)任務(wù),它不依賴于其它的任何任務(wù)的完成。 單元測(cè)試所關(guān)注的常常是方法是否滿足API契約(對(duì)應(yīng)用編程接口API的一種看法,把它看作是調(diào)用者和被調(diào)用者之間的正式協(xié)定)。4單元

2、測(cè)試的好處單元測(cè)試的好處 單元測(cè)試可以幫助您在開(kāi)發(fā)過(guò)程中驗(yàn)證和優(yōu)化設(shè)計(jì)。 單元測(cè)試可以降低不確定性從而降低風(fēng)險(xiǎn)。 單元測(cè)試用例可以當(dāng)作文檔使用。 單元測(cè)試有利于后期可能會(huì)進(jìn)行的回歸測(cè)試。 單元測(cè)試便于日常開(kāi)發(fā)流程的維護(hù)。當(dāng)把一天的工作任務(wù)準(zhǔn)備提交到VSS上時(shí),只需要運(yùn)行當(dāng)天所有的測(cè)試用例,確保全部通過(guò)了之后再提交,這樣就能保證編寫(xiě)代碼的正確性。5Mock 對(duì)象與 EasyMock 簡(jiǎn)介 單元測(cè)試與單元測(cè)試與 Mock Mock 方法方法 -單元測(cè)試是對(duì)應(yīng)用中的某一個(gè)模塊的功能進(jìn)行驗(yàn)證。在單元測(cè)試中,我們常遇到的問(wèn)題是應(yīng)用中其它的協(xié)同模塊尚未開(kāi)發(fā)完成,或者被測(cè)試模塊需要和一些不 容易構(gòu)造、比較復(fù)

3、雜的對(duì)象進(jìn)行交互。另外,由于不能肯定其它模塊的正確性,我們也無(wú)法確定測(cè)試中發(fā)現(xiàn)的問(wèn)題是由哪個(gè)模塊引起的。 -Mock 對(duì)象能夠模擬其它協(xié)同模塊的行為,被測(cè)試模塊通過(guò)與 Mock 對(duì)象協(xié)作,可以獲得一個(gè)孤立的測(cè)試環(huán)境。此外,使用 Mock 對(duì)象還可以模擬在應(yīng)用中不容易構(gòu)造(如 HttpServletRequest 必須在 Servlet 容器中才能構(gòu)造出來(lái))和比較復(fù)雜的對(duì)象(如 JDBC 中的 ResultSet 對(duì)象),從而使測(cè)試順利進(jìn)行。6l安裝安裝 EasyMockEasyMock -EasyMock 是采用 MIT license 的一個(gè)開(kāi)源項(xiàng)目,您可以在 Sourceforge 上下載

4、到相關(guān)的 zip 文件。目前您可以下載的 EasyMock 最新版本是2.3,它需要運(yùn)行在 Java 5.0 平臺(tái)上。如果您的應(yīng)用運(yùn)行在 Java 1.3 或 1.4 平臺(tái)上,您可以選擇 EasyMock1.2。在解壓縮 zip 包后,您可以找到 easymock.jar 這個(gè)文件。如果您使用 Eclipse 作為 IDE,把 easymock.jar 添加到項(xiàng)目的 Libraries 里就可以使用了(如下圖所示)。此外,由于我們的測(cè)試用例運(yùn)行在 JUnit 環(huán)境中,因此您還需要 JUnit.jar(版本3.8.1以上)。 7下圖是Eclipse中項(xiàng)目TestMockProj的Librarie

5、s8使用使用 EasyMock 進(jìn)行單元測(cè)試進(jìn)行單元測(cè)試 通過(guò) EasyMock,我們可以為指定的接口動(dòng)態(tài)的創(chuàng)建 Mock 對(duì)象,并利用 Mock 對(duì)象來(lái)模擬協(xié)同模塊或是領(lǐng)域?qū)ο?,從而使單元測(cè)試順利進(jìn)行。這個(gè)過(guò)程大致可以劃分為以下幾個(gè)步驟: -使用 EasyMock 生成 Mock 對(duì)象 -設(shè)定 Mock 對(duì)象的預(yù)期行為和輸出 -將 Mock 對(duì)象切換到 Replay 狀態(tài) -調(diào)用 Mock 對(duì)象方法進(jìn)行單元測(cè)試 -對(duì) Mock 對(duì)象的行為進(jìn)行驗(yàn)證。 接下來(lái),我們將對(duì)以上的幾個(gè)步驟逐一進(jìn)行說(shuō)明。9l使用 EasyMock 生成 Mock 對(duì)象 -根據(jù)指定的接口或類 , EasyMock 能夠動(dòng)

6、態(tài)的創(chuàng)建 Mock 對(duì)(EasyMock 默認(rèn)只支持為接口生成 Mock 對(duì)象,如果需要為 類生成 Mock 對(duì)象,在EasyMock 的主頁(yè)上有擴(kuò)展包可以實(shí)現(xiàn) 此 功能),我們以 MyListener接口為例說(shuō)明EasyMock的功能。 清單1,接口MyListener: publicpublic interfaceinterface MyListener voidvoid documentAdded(String title); void void documentChanged(String title); voidvoid documentRemoved(String title);

7、byte byte voteForRemoval(String title); byte byte voteForRemovals(String title);10 通常,構(gòu)建一個(gè)真實(shí)的 RecordSet 對(duì)象需要經(jīng)過(guò)一個(gè)復(fù)雜的過(guò)程:在開(kāi)發(fā)過(guò)程中,開(kāi)發(fā)人員通常會(huì)編寫(xiě)一個(gè) DBUtility 類來(lái)獲取數(shù)據(jù)庫(kù)連接 Connection,并利用 Connection 創(chuàng)建一個(gè) Statement。執(zhí)行一個(gè) Statement 可以獲取到一個(gè)或多個(gè) ResultSet 對(duì)象。這樣的構(gòu)造過(guò)程復(fù)雜并且依賴于數(shù)據(jù)庫(kù)的正確運(yùn)行。數(shù)據(jù)庫(kù)或是數(shù)據(jù)庫(kù)交互模塊出現(xiàn)問(wèn)題,都會(huì)影響單元測(cè)試的結(jié)果。 我們可以使用 Eas

8、yMock 動(dòng)態(tài)構(gòu)建MyListener接口的 Mock 對(duì)象來(lái)解決這個(gè)問(wèn)題。一些簡(jiǎn)單的測(cè)試用例只需要一個(gè) Mock 對(duì)象,這時(shí),我們可以用以下的方法來(lái)創(chuàng)建 Mock 對(duì)象: 11 MyListener mock = MyListener mock = createMockcreateMock(MyListener.class);(MyListener.class); 其中 createMock 是 org.easymock.EasyMock 類所提供的靜態(tài)方法,你可以通過(guò) static import 將其引入(注:static import 是 java 5.0 所提供的新特性)。 如果需要

9、在相對(duì)復(fù)雜的測(cè)試用例中使用多個(gè) Mock 對(duì)象,EasyMock 提供了另外一種生成和管理 Mock 對(duì)象的機(jī)制: IMocksControl control = EasyMock.createControl(); java.sql.Connection mockConnection = control.createMock(Connection.class); java.sql.Statement mockStatement = control.createMock(Statement.class); MyListener mock = control.createMock(MyListen

10、er.class); 12 EasyMock 類的 createControl 方法能創(chuàng)建一個(gè)接口 IMocksControl 的對(duì)象,該對(duì)象能創(chuàng)建并管理多個(gè) Mock 對(duì)象。如果需要在測(cè)試中使用多個(gè) Mock 對(duì)象,我們推薦您使用這一機(jī)制,因?yàn)樗诙鄠€(gè) Mock 對(duì)象的管理上提供了相對(duì)便捷的方法。 如果您要模擬的是一個(gè)具體類而非接口,那么您需要下載擴(kuò)展包 EasyMock Class Extension 2.2.2。在對(duì)具體類進(jìn)行模擬時(shí),您只要用 org.easymock.classextension.EasyMock 類中的靜態(tài)方法代替 org.easymock.EasyMock 類中的靜

11、態(tài)方法即可。 13 設(shè)定 Mock 對(duì)象的預(yù)期行為和輸出 添加 Mock 對(duì)象行為的過(guò)程通常可以分為以下3步: 1)、對(duì) Mock 對(duì)象的特定方法作出調(diào)用 2)、通過(guò) org.easymock.EasyMock 提供的靜態(tài)方 expectLastCall獲取上一次方法調(diào)用所對(duì)應(yīng)的 IExpectationSetters 實(shí)例 3)、通過(guò) IExpectationSetters 實(shí)例設(shè)定 Mock 對(duì) 象的預(yù)期輸 出。 14設(shè)定預(yù)期返回值設(shè)定預(yù)期返回值 Mock 對(duì)象的行為可以簡(jiǎn)單的理解為 Mock 對(duì)象方法的調(diào)用和方法調(diào)用所產(chǎn)生的輸出。在 EasyMock 2.3版中,對(duì) Mock 對(duì)象行為的

12、添加和設(shè)置是通過(guò)接口 IExpectationSetters 來(lái)實(shí)現(xiàn)的。Mock 對(duì)象方法的調(diào)用可能產(chǎn)生兩種類型的輸出: (1)、產(chǎn)生返回值; (2)、拋出異常。 接口 IExpectationSetters 提供了多種設(shè)定預(yù)期輸出的方法,其中和設(shè)定返回值相對(duì)應(yīng)的是 andReturn 方法: IExpectationSetters andReturn(T value); 15 我們?nèi)匀挥?MyListener 接口的 Mock 對(duì)象為例,如果希望方法 MyListener. voteForRemoval() 能夠刪除標(biāo)題為 “Ducument”的文件投票,并且返回值為42,那么你可以使用以下

13、的語(yǔ)句:expect(mock.voteForRemoval(“Document”).andReturn(bytebyte) 42); 以上的語(yǔ)句表示 mock 的 voteForRemoval 方法被調(diào)用一次,這次調(diào)用的返回值是42。有時(shí),我們希望某個(gè)方法的調(diào)用總是返回一個(gè)相同的值,為了避免每次調(diào)用都為 Mock 對(duì)象的行為進(jìn)行一次設(shè)定,我們可以用設(shè)置默認(rèn)返回值的方法: void andStubReturn(Object value); 16設(shè)定預(yù)期異常拋出設(shè)定預(yù)期異常拋出 對(duì)象行為的預(yù)期輸出除了可能是返回值外,還有可能是拋出 異常。EasyMock提供了設(shè)定預(yù)期拋出異常的方法: IExpe

14、ctationSetters andThrow(Throwable throwable); 和設(shè)定默認(rèn)返回值類似,EasyMock也提供了設(shè)定拋出默認(rèn)異常的函數(shù): void andStubThrow(Throwable throwable); 17設(shè)定預(yù)期方法調(diào)用次數(shù)設(shè)定預(yù)期方法調(diào)用次數(shù) 通過(guò)以上的函數(shù),您可以對(duì) Mock 對(duì)象特定行為的預(yù)期輸出進(jìn)行設(shè)定。除了對(duì)預(yù)期輸出進(jìn)行設(shè)定,EasyMock還允許用戶對(duì)方法的調(diào)用次數(shù)作出限制,常用的是 times 方法: IExpectationSetterstimes(int count); 假設(shè)我們要把MyListen接口的documentChange

15、d方法調(diào)用三次,可以這樣: mock.documentAdded(Document); mock.documentChanged(Document); expectLastCall().times(3); 也可以簡(jiǎn)寫(xiě)為:expect(mock.documentChanged(Document).time(3); 18 除了設(shè)定確定的調(diào)用次數(shù),EasyMock還提供了另外幾種設(shè)定非準(zhǔn)確調(diào)用次數(shù)的方法:times(int minTimes, int maxTimes):該方法最少被調(diào)用 minTimes 次,最多被調(diào)用 maxTimes 次。 atLeastOnce():該方法至少被調(diào)用一次。an

16、yTimes():該方法可以被調(diào)用任意次。 某些方法的返回值類型是 void,對(duì)于這一類方法,我們無(wú)需設(shè)定返回值,只要設(shè)置調(diào)用次數(shù)就可以了。以 MyListener接口的 documentChanged方法為例,假設(shè)在測(cè)試過(guò)程中,該方法被調(diào)用3至5次: mock.documentAdded(Document); mock.documentChanged(Document); expectLastCall().times(3,5); 19將 Mock 對(duì)象切換到 Replay 狀態(tài) -在生成 Mock 對(duì)象和設(shè)定 Mock 對(duì)象行為兩個(gè)階段,Mock 對(duì)象的狀態(tài)都是 Record 。在這個(gè)階段,

17、Mock 對(duì)象會(huì)記錄用戶對(duì)預(yù)期行為和輸出的設(shè)定。 -在 使用 Mock 對(duì)象進(jìn)行實(shí)際的測(cè)試前,我們需要將 Mock 對(duì)象的狀態(tài)切換為 Replay。在 Replay 狀態(tài),Mock 對(duì)象能夠根據(jù)設(shè)定對(duì)特定的方法調(diào)用作出預(yù)期的響應(yīng)。將 Mock 對(duì)象切換成 Replay 狀態(tài)有兩種方式,您需要根據(jù) Mock 對(duì)象的生成方式進(jìn)行選擇。如果 Mock 對(duì)象是通過(guò) org.easymock.EasyMock 類提供的靜態(tài)方法 createMock 生成的,那么 EasyMock 類提供了相應(yīng)的 replay 方法用于將 Mock 對(duì)象切換為 Replay 狀態(tài): replay(mock) 20 -如果

18、 Mock 對(duì)象是通過(guò) IMocksControl 接口提供的 createMock 方法生成的(前面介紹的第二種Mock對(duì)象生成方法),那么您依舊可以通過(guò) IMocksControl 接口對(duì)它所創(chuàng)建的所有 Mock 對(duì)象進(jìn)行切換: control.replay(); 以上的語(yǔ)句能將前面生成的 mockConnection、mockStatement 和 mockMyListener等3個(gè) Mock 對(duì)象都切換成 Replay 狀態(tài)。 21 調(diào)用 Mock 對(duì)象方法進(jìn)行單元測(cè)試 為更好的說(shuō)明 EasyMock 的功能,我們引入 TestMockProj 示例來(lái)解釋 Mock 對(duì)象在實(shí)際測(cè)試階段

19、的作用。其中所有的示例代碼都可以在 TestMockProj中找到。如果您使用的 IDE 是 Eclipse,在導(dǎo)入 TestMockProj工程之后您可以看到 Workspace 中增加的 project(如下圖所示)。 22 在Eclipse中導(dǎo)入TestMockProj工程文件之后,可以直接查看代碼 詳細(xì)清單,共包括MyClass,java,MyListener.java,MyClassTest.java 和ThrowableEquals.java四個(gè)JAVA文件。在MyClassTest.java中,以 測(cè)試MyClass中的addDocument方法為例進(jìn)行講解 1) 準(zhǔn)備工作,在s

20、etup方法中完成 首先創(chuàng)建了 MyListener的 Mock 對(duì)象 mock和MyClass的對(duì)象 classUnderTest,并把mock添加到classUnderTest對(duì)象中。 publicpublic voidvoid setup() mock = createMock(MyListener.classclass); classUnderTest = newnew MyClass() classUnderTest.addListener(mock); 2)記錄mock對(duì)象的預(yù)期行為 mock.documentAdded(New Document);233)調(diào)用了 replay()

21、,將 Mock 對(duì)象的狀態(tài)置為 Replay 狀態(tài) replay(mock);4)調(diào)用 Mock 對(duì)象方法進(jìn)行單元測(cè)試 classUnderTest.addDocument(New Document, newnew bytebyte0);5)對(duì) Mock 對(duì)象的行為進(jìn)行驗(yàn)證 verify(mock); 通過(guò)調(diào)用EasyMock 進(jìn)行單元測(cè)試,我們可以理清業(yè)務(wù)邏輯,盡早發(fā)現(xiàn)我們?cè)O(shè)計(jì)當(dāng)中存在的問(wèn)題。24 對(duì) Mock 對(duì)象的行為進(jìn)行驗(yàn)證 在利用 Mock 對(duì)象進(jìn)行實(shí)際的測(cè)試過(guò)程之后,我們還有一件事情沒(méi)有做:對(duì) Mock 對(duì)象的方法調(diào)用的次數(shù)進(jìn)行驗(yàn)證。為了驗(yàn)證指定的方法調(diào)用真的完成了,我們需要調(diào)用

22、verify 方法進(jìn)行驗(yàn)證。和 replay 方法類似,您需要根據(jù) Mock 對(duì)象的生成方式來(lái)選用不同的驗(yàn)證方式。如果 Mock對(duì)象是由 org.easymock.EasyMock 類提供的 createMock 靜態(tài)方法生成的,那么我們同樣采用 EasyMock 類的靜態(tài)方法 verify 進(jìn)行驗(yàn)證: verify(mock); 25 如果Mock對(duì)象是有 IMocksControl 接口所提供的 createMock 方法生成的,那么采用該接口提供的 verify 方法,就如前面講到的 IMocksControl 實(shí)例 control: control.verify(); 將對(duì) contr

23、ol 實(shí)例所生成的 Mock 對(duì)象 mockConnection、mockStatement 和 mock 等進(jìn)行驗(yàn)證。26在MyClassTest.java中,以addAndChangeDocument方法為例進(jìn)行講解。 publicpublic voidvoid addAndChangeDocument() mock.documentAdded(Document); mock.documentChanged(Document); expectLastCall().times(3); replay(mock); classUnderTest.addDocument(Document, new

24、new bytebyte0); classUnderTest.addDocument(Document, newnew bytebyte0); classUnderTest.addDocument(Document, newnew bytebyte0); classUnderTest.addDocument(Document, newnew bytebyte0); verify(mock); 27 現(xiàn)在要驗(yàn)證先增加一個(gè)Document,然后對(duì)它進(jìn)行了三次修改操作,那么方法times中的整數(shù)就應(yīng)該是3,如果是4或者5就會(huì)出錯(cuò)。如下圖:預(yù)期結(jié)果是5,實(shí)際執(zhí)行了3次。 28 Mock 對(duì)象的重用 為

25、了避免生成過(guò)多的 Mock 對(duì)象,EasyMock 允許對(duì)原有 Mock 對(duì)象進(jìn)行重用。要對(duì) Mock 對(duì)象重新初始化,我們可以采用 reset 方法。和 replay 和 verify 方法類似,EasyMock 提供了兩種 reset 方式:(1)、如果 Mock 對(duì)象是由 org.easymock.EasyMock 類中的靜態(tài) 方法 createMock 生成的,那么該 Mock 對(duì)象的可以EasyMock 類的靜態(tài)方法 reset 重新初始化;(2)、如果 Mock 方法是由 IMocksControl 實(shí)例的 createMock 方法生成的,那么該 IMocksControl 實(shí)例

26、方法 reset 的調(diào)用將 會(huì)把所有該實(shí)例創(chuàng)建的 Mock 對(duì)象重新初始化。在重新初始化之后,Mock 對(duì)象的狀態(tài)將被置為 Record 狀態(tài)。29 使用 EasyMock 進(jìn)行單元測(cè)試小結(jié) 如果您需要在單元測(cè)試中構(gòu)建 Mock 對(duì)象來(lái)模擬協(xié)同模塊或一些復(fù)雜對(duì)象,EasyMock 是一個(gè)可以選用的優(yōu)秀框架。EasyMock 提供了簡(jiǎn)便的方法創(chuàng)建 Mock 對(duì)象:通過(guò)定義 Mock 對(duì)象的預(yù)期行為和輸出,你可以設(shè)定該 Mock 對(duì)象在實(shí)際測(cè)試中被調(diào)用方法的返回值、異常拋出和被調(diào)用次數(shù)。通過(guò)創(chuàng)建一個(gè)可以替代現(xiàn)有對(duì)象的 Mock 對(duì)象,EasyMock 使得開(kāi)發(fā)人員在測(cè)試時(shí)無(wú)需編寫(xiě)自定義的 Mock 對(duì)象,從而避免了額外的編碼工作和因此引入錯(cuò)誤的機(jī)會(huì)。 30本次講座小結(jié)本次講座小結(jié) 測(cè)試包名和測(cè)試用例名稱的習(xí)慣取法 被測(cè)試java源文件包名: org.easymock.samples 單元測(cè)試用例java文件包名: .easymock.samples 被測(cè)試java源文件: MyClass.java 單元測(cè)試用例java文件包名: MyClassTest.java 不管是測(cè)試文件包名的取法,還是測(cè)試Java源文件名的取法,兩者都相差一個(gè)test ,當(dāng)然這只是一種習(xí)慣用法,并非一定要這樣

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝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ù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 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)論