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

下載本文檔

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

文檔簡介

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

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

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

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

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

6、態(tài)的創(chuàng)建 Mock 對(EasyMock 默認只支持為接口生成 Mock 對象,如果需要為 類生成 Mock 對象,在EasyMock 的主頁上有擴展包可以實現(xiàn) 此 功能),我們以 MyListener接口為例說明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)建一個真實的 RecordSet 對象需要經(jīng)過一個復(fù)雜的過程:在開發(fā)過程中,開發(fā)人員通常會編寫一個 DBUtility 類來獲取數(shù)據(jù)庫連接 Connection,并利用 Connection 創(chuàng)建一個 Statement。執(zhí)行一個 Statement 可以獲取到一個或多個 ResultSet 對象。這樣的構(gòu)造過程復(fù)雜并且依賴于數(shù)據(jù)庫的正確運行。數(shù)據(jù)庫或是數(shù)據(jù)庫交互模塊出現(xiàn)問題,都會影響單元測試的結(jié)果。 我們可以使用 Eas

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

9、在相對復(fù)雜的測試用例中使用多個 Mock 對象,EasyMock 提供了另外一種生成和管理 Mock 對象的機制: 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)建一個接口 IMocksControl 的對象,該對象能創(chuàng)建并管理多個 Mock 對象。如果需要在測試中使用多個 Mock 對象,我們推薦您使用這一機制,因為它在多個 Mock 對象的管理上提供了相對便捷的方法。 如果您要模擬的是一個具體類而非接口,那么您需要下載擴展包 EasyMock Class Extension 2.2.2。在對具體類進行模擬時,您只要用 org.easymock.classextension.EasyMock 類中的靜態(tài)方法代替 org.easymock.EasyMock 類中的靜

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

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

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

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

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

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

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

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

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

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

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

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

23、ol 實例所生成的 Mock 對象 mockConnection、mockStatement 和 mock 等進行驗證。26在MyClassTest.java中,以addAndChangeDocument方法為例進行講解。 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)在要驗證先增加一個Document,然后對它進行了三次修改操作,那么方法times中的整數(shù)就應(yīng)該是3,如果是4或者5就會出錯。如下圖:預(yù)期結(jié)果是5,實際執(zhí)行了3次。 28 Mock 對象的重用 為

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

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

溫馨提示

  • 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

提交評論