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

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

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

    我的漫漫程序之旅

    專注于JavaWeb開發(fā)
    隨筆 - 39, 文章 - 310, 評論 - 411, 引用 - 0
    數(shù)據(jù)加載中……

    EasyMock使用手記

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

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

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

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

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

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

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

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

    2 )設置模仿對象中的狀態(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 層架構中,我們都是面向接口編程的,我們定義了 DAO 接口,我們定義了 Service 接口,這樣做的優(yōu)點就是我們在測試時可以構造實現(xiàn)接口的 Mock 類。這里不得不提依賴注入,通過依賴注入,我們才能在測試時 set Mock 對象。這也說明,為了方便測試,我們不得不一步一步 重構代碼,而模式就在重構中自然地產(chǎn)生了。

    對于 Mock 對象,我們可以根據(jù) 合作者接口(或者是類) 實現(xiàn)具體的 Mock 類,這樣的 Mock 類實際上是 Stub 。有些情況下, Stub 是必要的。但對于諸如 DAO Service ,我們只關心在給定參數(shù)的情況下,調(diào)用的方法能夠返回預期的值,我們根本不關心其內(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 采用了范型技術,故創(chuàng)建的 Mock 對象不需要強制類型轉換。然后通過 “accountService.setAccountDAO(accountDAOMock);” 設置目標對象的合作者對象。

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

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

    4 (c) 處的 replay() 是結束錄制過程。 在調(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() 是用于在錄制和回放兩個步驟完成之后進行預期和實際結果的檢查。這里就是檢查 accountDAOMock 是否如預期一樣調(diào)用了 getByNameAndPwd 方法。

     

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

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

    等文章,一并感謝。



    posted on 2007-11-24 07:22 々上善若水々 閱讀(1723) 評論(0)  編輯  收藏 所屬分類: 軟件測試

    主站蜘蛛池模板: 手机在线免费视频| 亚洲AV无码一区二区三区电影 | 亚洲AV无码一区二区三区在线| 免费大片在线观看网站| 国产又大又粗又长免费视频| 最近2019中文免费字幕在线观看| 色偷偷噜噜噜亚洲男人| 亚洲精品视频免费观看| 免费无遮挡无遮羞在线看| 亚洲狠狠婷婷综合久久| 亚洲欧洲国产综合AV无码久久| 亚洲综合激情视频| 久久久综合亚洲色一区二区三区 | a级毛片毛片免费观看永久| 人妻仑刮八A级毛片免费看| 久久精品成人免费看| 国产无遮挡无码视频免费软件| 日韩版码免费福利视频| 色影音免费色资源| 五月婷婷亚洲综合| 精品国产免费观看久久久| 免费无码AV电影在线观看| 最近免费中文字幕4| 亚洲七七久久精品中文国产| 亚洲国产精品成人| 亚洲乳大丰满中文字幕| 亚洲情XO亚洲色XO无码| 亚洲国产精品yw在线观看| 国产亚洲玖玖玖在线观看| 亚洲成人激情小说| 中文字幕无码免费久久9一区9| 免费国产成人18在线观看| 女人被男人桶得好爽免费视频 | 啦啦啦手机完整免费高清观看| 国产成人A亚洲精V品无码| 国产亚洲美女精品久久久久狼| 国产∨亚洲V天堂无码久久久| 亚洲乱亚洲乱淫久久| 亚洲日本香蕉视频观看视频| 亚洲日本国产综合高清| a毛片在线看片免费|