<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    邊城愚人

    如果我不在邊城,我一定是在前往邊城的路上。

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      31 隨筆 :: 0 文章 :: 96 評論 :: 0 Trackbacks

    Mock 對象能夠模擬領域對象的部分行為,并且能夠檢驗運行結果是否和預期的一致。領域類將通過與 Mock 對象的交互,來獲得一個獨立的測試環境(引自《 精通 Spring——Java 輕量級架構開發實踐 》。

    在模仿對象中,我們定義了四個概念:

    1 目標對象:正在測試的對象

    2 合作者對象:由目標對象創建或獲取的對象

    3 模仿對象:遵循模仿對象模式的合作者的子類(或實現)

    4 特殊化對象:覆蓋創建方法以返回模仿對象而不是合作者的目標的子類

    一般來說,應用模仿對象的過程如下:

    1 )創建模仿對象的實例

    2 )設置模仿對象中的狀態和期望值

    3 )將模仿對象作為參數來調用域代碼

    4 )驗證模仿對象中的一致性

    那么,我們應該如何以及在哪里使用 Mock 對象呢?一般來說,對于目標對象中的合作者對象,在測試時如果其狀態或行為的實現嚴重地依賴外部資源(比如數據持久化中的 DAO ,比如負責發送電子郵件的類),或者團隊并行開發時,目標對象的合作者對象并沒有實現(比如 J2EE 中,橫向分工時,負責 Action 的調用 Service ,負責 Service 調用 DAO 時,相應的 Service DAO 沒有實現),這時我們就需要模仿這些類。其實,在做 J2EE 時,傳統的 N 層架構中,我們都是面向接口編程的,我們定義了 DAO 接口,我們定義了 Service 接口,這樣做的優點就是我們在測試時可以構造實現接口的 Mock 類。這里不得不提依賴注入,通過依賴注入,我們才能在測試時 set Mock 對象。這也說明,為了方便測試,我們不得不一步一步 重構代碼,而模式就在重構中自然地產生了。

    對于 Mock 對象,我們可以根據 合作者接口(或者是類) 實現具體的 Mock 類,這樣的 Mock 類實際上是 Stub 。有些情況下, Stub 是必要的。但對于諸如 DAO Service ,我們只關心在給定參數的情況下,調用的方法能夠返回預期的值,我們根本不關心其內部實現,這時候如果使用 Stub 的話就會產生不必要的代碼。我們需要的就是能 動態地生成 Mock 對象而不需要編寫它們的工具, EasyMock 就是這樣的工具。

    EasyMock 是一個 Mock 對象的類庫,現在的版本是 2.0 ,這個版本只支持 Mock 接口,如果需要 Mock 類,需要下載它的擴展包。

    下面通過一個具體的例子說明一下 Mock 對象的使用,我寫的例子就是測試 Service 類中的一個方法, Mock 的對象是 DAO

    首先是一個簡單的實體 bean Account:

    package ?easymocktest.domain;

    import
    ?org.apache.commons.lang.builder.ToStringBuilder;
    import
    ?org.apache.commons.lang.builder.ToStringStyle;

    public ? class ?Account? {

    ????
    private ?Long?id;
    ????
    private ?String?name;
    ????
    private ?String?pwd;
    ????
    ????
    public ?Long?getId()? {
    ????????
    return ?id;
    ????}

    ????
    public ? void ?setId(Long?id)? {
    ????????
    this .id? = ?id;
    ????}

    ????
    public ?String?getName()? {
    ????????
    return ?name;
    ????}

    ????
    public ? void ?setName(String?name)? {
    ????????
    this .name? = ?name;
    ????}

    ????
    public ?String?getPwd()? {
    ????????
    return ?pwd;
    ????}

    ????
    public ? void ?setPwd(String?pwd)? {
    ????????
    this .pwd? = ?pwd;
    ????}

    ????
    /**
    ?????*?
    @see ?java.lang.Object#toString()
    ?????
    */

    ????
    public ?String?toString()? {
    ????????
    return ? new ?ToStringBuilder( this ,?ToStringStyle.MULTI_LINE_STYLE)
    ????????????????.append(
    " name " ,? this .name).append( " pwd " ,? this .pwd).append( " id " ,
    ????????????????????????
    this .id).toString();
    ????}

    ????
    }

    ??????

    ????一個只含一個方法的 DAO AccountDAO:

    package ?easymocktest.dao;

    import ?easymocktest.domain. *
    ;
    public ? interface ?AccountDAO? {
    ????
    public ?Account?getByNameAndPwd(String?name,String?pwd);
    }

    ????

    ?

    ???一個同樣只含一個方法的 AccountService 接口:

    ?

    package ?easymocktest.service;

    import ?easymocktest.domain. *
    ;
    public ? interface ?AccountService? {
    ????
    public ?Account?getAccount(String?name,String?pwd);
    }

    ???與 AccountService 相應的實現類:

    package ?easymocktest.service.impl;

    import
    ?easymocktest.service.AccountService;
    import ?easymocktest.dao. *
    ;
    import
    ?easymocktest.domain.Account;
    public ? class ?AccountServiceImpl? implements ?AccountService? {

    ????
    private ?AccountDAO?accountDAO;

    ????
    public ?AccountDAO?getAccountDAO()? {
    ????????
    return ?accountDAO;
    ????}


    ????
    public ? void ?setAccountDAO(AccountDAO?accountDAO)? {
    ????????
    this .accountDAO? = ?accountDAO;
    ????}


    ????
    public ?Account?getAccount(String?name,?String?pwd)? {
    ????????
    return ? this .accountDAO.getByNameAndPwd(name,?pwd);
    ????}


    }


    ???這里我沒有實現 AccountDAO 接口,對于 Mock 測試來說,這也是不需要的。下面就是 AccountServiceImpl 的測試類 AccountServiceTest
    ???

    package ?easymocktest.service;

    import ?junit.framework. *
    ;
    import ?easymocktest.dao. *
    ;
    import ?easymocktest.domain. *
    ;
    import ?easymocktest.service.impl. *
    ;
    import ? static
    ?org.easymock.EasyMock.createMock;
    import ? static
    ?org.easymock.EasyMock.replay;
    import ? static
    ?org.easymock.EasyMock.reset;
    import ? static
    ?org.easymock.EasyMock.verify;
    import ? static
    ?org.easymock.EasyMock.expect;
    public ? class ?AccountServiceTest? extends ?TestCase {

    ????
    private ?AccountDAO?accountDAOMock;
    ????
    private ?AccountServiceImpl?accountService;
    ????
    ????@Override
    ????
    protected ? void ?setUp()? throws ?Exception? {
    ????????accountDAOMock?
    = ?createMock(AccountDAO. class );
    ????????accountService?
    = ? new ?AccountServiceImpl();
    ????????accountService.setAccountDAO(accountDAOMock);
    ????}

    ????
    ????
    public ? void ?testGetAccount() {
    ????????String?name?
    = ? " kafka " ;
    ????????String?pwd?
    = ? " 0102 " ;
    ????????Account?a?
    = ? new ?Account();
    ????????a.setName(name);
    ????????a.setPwd(pwd);
    ????????a.setId(
    new ?Long( 10 ));
    ????????reset(accountDAOMock);
    // (a)
    ????????expect(accountDAOMock.getByNameAndPwd(name,?pwd)).andReturn(a); // (b)
    ????????replay(accountDAOMock); // (c)
    ????????Account?b? = ?accountService.getAccount(name,?pwd);
    ????????assertEquals(a,?b);
    ????????verify(accountDAOMock);
    // (d)
    ????}

    }

    ???

    下面簡要的說明一下 Mock 對象的工作過程:

    1 )在 setUp() 中,通過 “accountDAOMock = createMock(AccountDAO.class);” (這里使用了 java5 中的靜態導入),創建 AccountDAO Mock 對象,由于 EasyMock 采用了范型技術,故創建的 Mock 對象不需要強制類型轉換。然后通過 “accountService.setAccountDAO(accountDAOMock);” 設置目標對象的合作者對象。

    2 )對于測試方法 “testGetAccount()” (a) 處的 reset() 方法是將 Mock 對象復位,也就是重新設置 Mock 對象的狀態和行為。由于此處是第一次調用 Mock 對象,可以不必使用 reset() 方法。

    3 (b) expect() 是錄制 Mock 對象方法的調用,其參數就是 Mock 對象的方法,其中如果調用的方法有返回值,要通過 andReturn() 方法設置預期的返回值。

    4 (c) 處的 replay() 是結束錄制過程。 在調用 replay() 方法之前的狀態, EashMock 稱之為 “record 狀態 。該狀態下, Mock 對象不具備行為(即模擬接口的實現),它僅僅記錄方法的調用。在調用 replay() 后,它才以 Mock 對象預期的行為進行工作,檢查預期的方法調用是否真的完成。

    5 (d) 處的 verify() 是用于在錄制和回放兩個步驟完成之后進行預期和實際結果的檢查。這里就是檢查 accountDAOMock 是否如預期一樣調用了 getByNameAndPwd 方法。

    ?

    對于上面的舉例,它可能并不具有實際的價值,這里我只想拋磚引玉。在 N 層架構的 Java 程序中, Mock 對象在單元測試中正發揮著越來越重要的作用。我現在看到的是,在 Service 層與 Web 層, Mock 對象能很好的被應用。有人覺得在 Persistence 層也應該使用 Mock 對象,但就像我們所知道的,在使用 Hibernate Ibatis ORM 工具的情況下,我們的 Persistence 層的測試主要測試的就是那些配置文件、查詢語句等(實際上是集成測試),如果還 Mock 的話,就失去了測試的意義。

    ???對于 Mock 的更多的信息,你可以訪問Mock Objects,在本文寫作的過程中,參考了使用模仿對象進行單元測試

    等文章,一并感謝。

    posted on 2007-04-26 08:35 kafka0102 閱讀(4045) 評論(1)  編輯  收藏 所屬分類: TDD

    評論

    # re: EasyMock使用手記 2009-05-07 15:04 josdoc
    Java開源文檔
    www.josdoc.com
    轉載了您的文章,若有異議請告知,謝謝!  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 国产亚洲Av综合人人澡精品| 亚洲综合一区二区三区四区五区| 免费人成又黄又爽的视频在线电影| 一区二区无码免费视频网站| 亚洲午夜国产精品| 免费精品人在线二线三线区别| 亚洲一区二区三区免费观看| 国产精品免费观看久久| 亚洲粉嫩美白在线| 免费观看国产小粉嫩喷水| 青娱乐在线视频免费观看| 久久久精品国产亚洲成人满18免费网站 | 成人国产网站v片免费观看| 亚洲AV中文无码乱人伦| 久久毛片免费看一区二区三区| 亚洲精品无码永久中文字幕| 国产日产亚洲系列| 东方aⅴ免费观看久久av| 亚洲伦理一区二区| 青青青国产在线观看免费网站 | 免费不卡视频一卡二卡| 亚洲精品一卡2卡3卡四卡乱码| www亚洲一级视频com| 国产一级淫片a免费播放口| 亚洲欧洲久久精品| 精品久久免费视频| 国产一精品一AV一免费| 亚洲AV综合色区无码二区偷拍| 永久免费无码网站在线观看| 久久嫩草影院免费看夜色| 亚洲精品在线免费观看| 国产aa免费视频| 久久午夜夜伦鲁鲁片无码免费| 亚洲va在线va天堂成人| 国产专区一va亚洲v天堂| 亚洲免费福利视频| 有码人妻在线免费看片| 亚洲小视频在线播放| 亚洲精品国产自在久久| 一二三四在线播放免费观看中文版视频| 色噜噜狠狠色综合免费视频|