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

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

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

    邊城愚人

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

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

    Mock 對象能夠模擬領(lǐng)域?qū)ο蟮牟糠中袨椋⑶夷軌驒z驗運行結(jié)果是否和預期的一致。領(lǐng)域類將通過與 Mock 對象的交互,來獲得一個獨立的測試環(huán)境(引自《 精通 Spring——Java 輕量級架構(gòu)開發(fā)實踐 》。

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

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

    2 合作者對象:由目標對象創(chuàng)建或獲取的對象

    3 模仿對象:遵循模仿對象模式的合作者的子類(或?qū)崿F(xiàn))

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

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

    1 )創(chuàng)建模仿對象的實例

    2 )設(shè)置模仿對象中的狀態(tài)和期望值

    3 )將模仿對象作為參數(shù)來調(diào)用域代碼

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

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

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

    EasyMock 是一個 Mock 對象的類庫,現(xiàn)在的版本是 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 相應的實現(xiàn)類:

    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);
    ????}


    }


    ???這里我沒有實現(xiàn) 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 中的靜態(tài)導入),創(chuàng)建 AccountDAO Mock 對象,由于 EasyMock 采用了范型技術(shù),故創(chuàng)建的 Mock 對象不需要強制類型轉(zhuǎn)換。然后通過 “accountService.setAccountDAO(accountDAOMock);” 設(shè)置目標對象的合作者對象。

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

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

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

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

    ?

    對于上面的舉例,它可能并不具有實際的價值,這里我只想拋磚引玉。在 N 層架構(gòu)的 Java 程序中, Mock 對象在單元測試中正發(fā)揮著越來越重要的作用。我現(xiàn)在看到的是,在 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
    轉(zhuǎn)載了您的文章,若有異議請告知,謝謝!  回復  更多評論
      


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


    網(wǎng)站導航:
     
    主站蜘蛛池模板: 美女视频黄免费亚洲| 亚洲网站视频在线观看| 中文毛片无遮挡高潮免费| 一级做a爰片久久毛片免费看| 亚洲国产片在线观看| 亚洲一区爱区精品无码| 国产又大又粗又硬又长免费 | 久久久久国产精品免费免费搜索 | 国产亚洲精品美女久久久| www国产亚洲精品久久久| 午夜dj在线观看免费视频| 国产福利视精品永久免费| 无码中文字幕av免费放dvd| 中文字幕的电影免费网站| 边摸边吃奶边做爽免费视频网站| 亚洲综合av一区二区三区| 亚洲国产成人精品电影| 2022年亚洲午夜一区二区福利| 亚洲色精品vr一区二区三区| 亚洲区小说区图片区| 国产一级特黄高清免费大片| 操美女视频免费网站| 美女视频黄免费亚洲| 青青青国产在线观看免费| h片在线免费观看| 久久精品无码专区免费青青| 久9这里精品免费视频| 久久九九AV免费精品| 暖暖免费日本在线中文| 国产无遮挡无码视频免费软件| 久久成人18免费网站| 国产成人精品免费视频大全| 一区二区免费在线观看| 成年网站免费入口在线观看| 有色视频在线观看免费高清在线直播| 另类小说亚洲色图| a级毛片免费网站| 免费无码一区二区三区蜜桃| 日韩精品免费在线视频| 午夜老司机永久免费看片| 成人浮力影院免费看|