您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 >
EasyMock使用方法與原理剖析
作者:網(wǎng)絡轉載 發(fā)布時間:[ 2013/2/21 13:32:40 ] 推薦標簽:

我們知道 Mock 對象有兩種創(chuàng)建方式:一種是通過 EasyMock 類提供的 createMock 方法創(chuàng)建,另一種是通過 EasyMock 類的 createControl 方法得到一個 IMocksControl 實例,再由這個 IMocksControl 實例創(chuàng)建 Mock 對象。其實,無論通過哪種方法獲得 Mock 對象,EasyMock 都會生成一個 IMocksControl 的實例,只不過第一種方式中的 IMocksControl 的實例對開發(fā)人員不可見而已。這個 IMocksControl 的實例,其實是 MocksControl 類的一個對象。MocksControl 類提供了 andReturn、andThrow、times、createMock 等方法。

MocksControl 類中包含了兩個重要的成員變量,分別是接口 IMocksBehavior 和 IMocksControlState 的實例。其中,IMocksBehavior 的實現(xiàn)類 MocksBehavior 是 EasyMock 的核心類,它保存著一個 ExpectedInvocationAndResult 對象的一個列表,而 ExpectedInvocationAndResult 對象中包含著 Mock 對象方法調用和預期結果的映射。MocksBehavior 類提供了 addExpected 和 addActual 方法用于添加預期行為和實際調用。

MocksControl 類中包含的另一個成員變量是 IMocksControlState 實例。IMocksControlState 擁有兩個不同的實現(xiàn)類:RecordState 和 ReplayState。顧名思義,RecordState 是 Mock 對象在 Record 狀態(tài)時的支持類,它提供了 invoke 方法在 Record 狀態(tài)下的實現(xiàn)。此外,它還提供了 andReturn、andThrow、times 等方法的實現(xiàn)。ReplayState 是 Mock 對象在 Replay 狀態(tài)下的支持類,它提供了 invoke 方法在 Replay 狀態(tài)下的實現(xiàn)。在 ReplayState 中,andReturn、andThrow、times 等方法的實現(xiàn)都是拋出IllegalStateException,因為在 Replay 階段,開發(fā)人員不應該再調用這些方法。

當我們調用 MocksControl 的 createMock 方法時,該方法首先會生成一個 JavaProxyFactory 類的對象。JavaProxyFactory 是接口 IProxyFactory 的實現(xiàn)類,它的主要功能是通過 java.lang.reflect.Proxy 對指定的接口創(chuàng)建動態(tài)代理實例,也是開發(fā)人員在外部看到的 Mock 對象。

在創(chuàng)建動態(tài)代理的同時,應當提供 InvocationHandler 的實現(xiàn)類。MockInvocationHandler 實現(xiàn)了這個接口,它的 invoke 方法主要的功能是根據(jù) Mock 對象狀態(tài)的不同而分別調用 RecordState 的 invoke 實現(xiàn)或是 ReplayState 的 invoke 實現(xiàn)。

創(chuàng)建 Mock 對象

下圖是創(chuàng)建 Mock 對象的時序圖:

圖5:創(chuàng)建 Mock 對象時序圖

當 EasyMock 類的 createMock 方法被調用時,它首先創(chuàng)建一個 MocksControl 對象,并調用該對象的 createMock 方法創(chuàng)建一個 JavaProxyFactory 對象和一個 MockInvocationHandler 對象。JavaProxyFactory 對象將 MockInvocationHandler 對象作為參數(shù),通過 java.lang.reflect.Proxy 類的 newProxyInstance 靜態(tài)方法創(chuàng)建一個動態(tài)代理。

記錄 Mock 對象預期行為

記錄 Mock 的預期行為可以分為兩個階段:預期方法的調用和預期輸出的設定。在外部程序中獲得的 Mock 對象,其實是由 JavaProxyFactory 創(chuàng)建的指定接口的動態(tài)代理,所有外部程序對接口方法的調用,都會指向 InvocationHandler 實現(xiàn)類的 invoke 方法。在 EasyMock 中,這個實現(xiàn)類是 MockInvocationHandler。下圖是調用預期方法的時序圖:

圖6:調用預期方法時序圖

當 MockInvocationHandler 的 invoke 方法被調用時,它首先通過 reportLastControl 靜態(tài)方法將 Mock 對象對應的 MocksControl 對象報告給 LastControl 類,LastControl 類將該對象保存在一個 ThreadLocal 變量中。接著,MockInvocationHandler 將創(chuàng)建一個 Invocation 對象,這個對象將保存預期調用的 Mock 對象、方法和預期參數(shù)。

在記錄 Mock 對象預期行為時,Mock 對象的狀態(tài)是 Record 狀態(tài),因此 RecordState 對象的 invoke 方法將被調用。這個方法首先調用 LastControl 的 pullMatchers 方法獲取參數(shù)匹配器。如果您還記得自定義參數(shù)匹配器的過程,應該能想起參數(shù)匹配器被調用時會將實現(xiàn)類的實例報告給 EasyMock,而這個實例終保存在 LastControl 中。如果沒有指定參數(shù)匹配器,默認的匹配器將會返回給 RecordState。

根據(jù) Invocation 對象和參數(shù)匹配器,RecordState 將創(chuàng)建一個 ExpectedInvocation 對象并保存下來。

在對預期方法進行調用之后,我們可以對該方法的預期輸出進行設定。我們以

expectLastCall().andReturn(X value).times(int times)

 

為例說明。如果 times 方法未被顯式的調用,EasyMock 會默認作為 times(1) 處理。下圖是設定預期輸出的時序圖:

圖7:設定預期輸出時序圖

在預期方法被調用時,Mock 對象對應的 MocksControl 對象引用已經(jīng)記錄在 LastControl 中,expectLastCall 方法通過調用 LastControl 的 lastControl 方法可以獲得這個引用。MocksControl 對象的 andReturn 方法在 Mock 對象 Record 狀態(tài)下會調用 RecordState 的 andReturn 方法,將設定的預期輸出以 Result 對象的形式記錄下來,保存在 RecordState 的 lastResult 變量中。

當 MocksControl 的 times 方法被調用時,它會檢查 RecordState 的 lastResult 變量是否為空。如果不為空,則將 lastResult 和預期方法被調用時創(chuàng)建的 ExpectedInvocation 對象一起,作為參數(shù)傳遞給 MocksBehavior 的 addExpected 方法。MocksBehavior 的 addExpected 方法將這些信息保存在數(shù)據(jù)列表中。

在 Replay 狀態(tài)下調用 Mock 對象方法

EasyMock 類的 replay 方法可以將 Mock 對象切換到 Replay 狀態(tài)。在 Replay 狀態(tài)下,Mock 對象將根據(jù)之前的設定返回預期輸出。下圖是 Replay 狀態(tài)下 Mock 對象方法調用的時序圖:

圖8:調用 Mock 對象方法時序圖

在 Replay 狀態(tài)下,MockInvocationHandler 會調用 ReplayState 的 invoke 方法。該方法會把 Mock 對象通過 MocksBehavior 的 addActual 方法添加到實際調用列表中,該列表在 verify 方法被調用時將被用到。同時,addActual 方法會根據(jù)實際方法調用與預期方法調用進行匹配,返回對應的 Result 對象。調用 Result 對象的 answer 方法可以獲取該方法調用的輸出。

6.使用 EasyMock 進行單元測試小結

如果您需要在單元測試中構建 Mock 對象來模擬協(xié)同模塊或一些復雜對象,EasyMock 是一個可以選用的框架。EasyMock 提供了簡便的方法創(chuàng)建 Mock 對象:通過定義 Mock 對象的預期行為和輸出,你可以設定該 Mock 對象在實際測試中被調用方法的返回值、異常拋出和被調用次數(shù)。通過創(chuàng)建一個可以替代現(xiàn)有對象的 Mock 對象,EasyMock 使得開發(fā)人員在測試時無需編寫自定義的 Mock 對象,從而避免了額外的編碼工作和因此引入錯誤的機會。

上一頁12345下一頁
軟件測試工具 | 聯(lián)系我們 | 投訴建議 | 誠聘英才 | 申請使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd