<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
    轉載了您的文章,若有異議請告知,謝謝!  回復  更多評論
      


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


    網站導航:
     
    主站蜘蛛池模板: 亚洲欧洲日产国码二区首页 | 亚洲伊人久久大香线焦| 久久亚洲国产成人精品无码区| 在线观看免费毛片| www.999精品视频观看免费| **一级毛片免费完整视| 日韩插啊免费视频在线观看 | 国产成A人亚洲精V品无码性色 | 国产91精品一区二区麻豆亚洲| 可以免费观看一级毛片黄a | 国产国拍亚洲精品福利 | 久久久久久久久免费看无码| 亚洲不卡影院午夜在线观看| 亚洲第一福利网站在线观看| 亚洲午夜久久久久久噜噜噜| 久久精品国产亚洲AV高清热 | 亚洲国产精品ⅴa在线观看| www免费黄色网| 黄在线观看www免费看| 国产片免费在线观看| 99在线观看视频免费| 国产精品免费大片| 18禁亚洲深夜福利人口| 亚洲视频在线播放| 亚洲免费在线观看| 免费一看一级毛片人| 4hu四虎最新免费地址| 亚洲精品国产摄像头| 在线观看亚洲一区二区| 亚洲av网址在线观看| 国产亚洲精AA在线观看SEE| 亚洲av无码乱码国产精品fc2| 亚洲精品午夜无码电影网| 亚洲黄黄黄网站在线观看| 日韩精品免费电影| 久久免费观看国产精品| eeuss影院ss奇兵免费com| 春暖花开亚洲性无区一区二区| 亚洲成在人线电影天堂色| 亚洲综合av一区二区三区| 亚洲日韩精品无码AV海量|