MockObjects的選擇:EasyMock與JMock的比較

MockObjects的選擇:EasyMockJMock的比較

本文假設讀者已經瞭解了MockObjects的使用目的和基本方式,不對MockTest之類的技術作過多解釋。僅提醒一句:不要測試你的MockObjects”

本文作爲一個評測結果的同時,也可以作爲EasyMockjMock的簡短教程。他們本身都很易用,可惜帶的示例過於複雜,都用了過多的模式。看過本文的例子,相信就可以從容的在項目中使用了。

Java中常用的MockObjectsEasyMockjMock等。其中EasyMock開發較早,已經出了1.1版本,而jMock前幾天纔剛推出了1.0 final。作爲剛成熟的小弟弟,jMock有什麼競爭實力呢?

本比較針對於以下幾個方面,代碼請見附件。

1 是否能夠對具體類進行模擬(當然,對接口模擬是基本功能)

2 是否能夠對方法名,參數,返回值進行動態控制

3 基本代碼行數

4 是否能夠對具有構造參數的具體類模擬

    現在比較開始了。首先製作若干測試文件,很簡單。要模擬的有一個接口和一個具體類,叫做TheInterfaceToMockTheClassToMock,另外,提供方法SampleReturn sampleMethod(Parameter p);以及同名無參數方法。

    第一個測試是針對TheInterfaceToMock,提供ParameterImplSampleReturnImpl作爲期待的參數和返回值。

    jMock代碼如下:  

public class JMockUsage extends MockObjectTestCase {

    public void testReturnValueWithParemeter(){       

        // 構造Mock控制器

        Mock m = new Mock(TheInterfaceToMock.class);

        // 這是要測試MockObject

        TheInterfaceToMock mock = (TheInterfaceToMock) m.proxy();

        // 期待的返回值

        SampleReturn sr = new SampleReturnImpl();

        // 期待的參數

        Parameter p = new ParameterImpl();

       

        // 控制器,期待一次,方法sampleMethod,參數等於p(equals),將返回sr

        m.expects(once()).method("sampleMethod")

.with(eq(p)).will(returnValue(sr));

              

        // 正式執行mockobject

        SampleReturn ret = mock.sampleMethod(new ParameterImpl());

        // 確定返回值是相同的

        assertSame(sr,ret);

    }

 

}

 

相同功能的easyMcok代碼如下:

public class EasyMockUsage extends TestCase {

    public void testReturnValueWithParameter(){       

        // 構造mock控制器

        MockControl control

 = MockControl.createControl(TheInterfaceToMock.class);

        // 這是要測試的MockObject

        TheInterfaceToMock mock

 = (TheInterfaceToMock) control.getMock();

        // 這是要返回的值

        SampleReturn sr = new SampleReturnImpl();

        // 這是要傳入的參數

        Parameter p = new ParameterImpl();

       

        // 恢復到記錄(record)狀態

        control.reset();

        // 首先記錄sampleMethod方法

        mock.sampleMethod(p);

        // 設定該方法的返回值

        control.setReturnValue(sr);

        // 切換狀態爲回覆(reply)

        control.replay();       

        // 正式執行mock object的方法,明顯的,參數值是equals而不是same

        SampleReturn ret = mock.sampleMethod(new ParameterImpl());

       

        // 確定返回值是需要的值

        assertSame(sr,ret);      

    }

    從上面的代碼可以看到,同樣的功能,二者的行數相差3行。其主要原因,就是easyMcokMock機制是基於狀態,首先是錄製狀態,記錄下來待測的方法和參數,返回值等,然後切換爲回覆狀態。而jMock沒有切換這一步,直接將參數返回值用一句話寫出來。確實是一句話:期待一次,方法sampleMethod,參數等於p(equals),將返回sr。其中的一些輔助函數,例如returnValue,eq等等,位於父類MockTestCase

    結論

 

    1 如果不能提供MockTestCase作爲父類,請使用EasyMock

    2 如果需要批量或動態生成測試,請使用更規則的jMock

    3 如果喜歡看起來行數少一些,請用jMock

    4 如果對狀態切換看不順眼,請用Mock

 

    下面進行具體類測試,一個共同的點是,二者均使用了CGLIB作爲增強器,因此效率差別幾乎沒有。將上面的測試稍稍修改,將TheInterfaceToMock改爲TheClassToMock。發生了以下變化。

    jMock,需要將import替換爲新的import,代碼中其他部分完全不變!

原來

import org.jmock.Mock;

import org.jmock.MockObjectTestCase;

改爲:

import org.jmock.cglib.Mock;

import org.jmock.cglib.MockObjectTestCase;

 

    這是個相當體貼的設計,保證了接口的一致性。對於一套API來說,同樣的類卻有不同的使用方法是個噩夢。

    easyMock,需要新增加一個import。並且修改一些聲明的地方。   

原來

import org.easymock.MockControl;

增加

import org.easymock.classextension.MockClassControl;

 

 

// mock控制器

MockControl control = MockClassControl.createControl(TheClassToMock.class);

 

其他部分不需要變化。雖然這有些變化,但是變化帶來了其他的好處,就是:能夠支持帶有構造參數的具體類,而jMock不支持。這對於大量使用了PicoContainer的代碼來說不啻是一個福音。

結論

 

    5 如果需要構造參數,只能使用easyMock

    6 如果喜歡用相同的API操作並且不在乎構造參數,請用jMock

    7 如果願意等待下一版本的jMock提供構造參數支持,請用jMock

 

參考比較表:

 

EasyMock

jMock

通過接口模擬

控制方法有效次數

定製參數匹配

不需要狀態轉換

具體類模擬

具體類可有構造參數

接口統一

條件代碼在一行中完成

支持其他參數規則,如not

自驗證 verify()

綜上,我選擇了jMock。不過想想看,easyMock3個類實現了大多數常用功能,很不簡單啊。而jMock,如果能夠提供對Constructor injection的支持就完美了。遺憾。不過從設計上看,jMock裏的模式使用堪稱典範,很好看哦。

本人對easyMock使用經驗不多,如有謬誤請指出。

下載地址:

http://www.jmock.org

http://www.easymock.org

比較代碼:

http://icecloud.51.net/data/mockobjects.zip

需要:

JUnit3.8.1Cglib2jMock1.0EasyMock1.1

   


版權聲明:
本文由冰雲完成,作者保留中文版權。
未經許可,不得使用於任何商業用途。
歡迎轉載,但請保持文章及版權聲明完整。
如需聯絡請發郵件:
icecloud(AT)sina.com
Blog:http://icecloud.51.net
 


 

 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章