Java單元測試進階之如何打樁(用easymock輕松打樁)


打樁(mock)是單元測試的重要內容和難點,學好打樁的技術,做單元測試基本就沒什么困難了。 

       mock有兩種,一種是靜態的,一種是動態的。靜態的就是在寫測試代碼之前根據需要打樁的類生成另外一個類,這個類就是mock object。動態的就是mock object是在測試代碼運行的時候才生成的。所以很明顯,動態打樁比靜態打樁要方便地多。本章就是介紹動態打樁的工具。

        早期的動態mock工具只能夠mock接口,而不能夠mock類;現在的mock工具無論是mock接口還是類都能夠輕松完成了。

        easymock就是其中的佼佼者,easymock現在已經是2.2版本了,本文使用的是easymock1.2_Java1.5版本。使用easymock能夠輕松的mock任何接口,但如果想mock類,那還需要另外一個lib,就是easymockclassextension,使用了這個工具,你就能輕松地mock你要的任何類了。本文使用的是easymockclassextension1.2,使用這個庫必須要cglib這個jar包,而cglib又需要asm的jar包,所以要搭建好環境還得花些時間,不過當你把環境搞好之后,你便會發現物超所值,從此以后打樁無難事了。cglib和asm的版本一定要適配,要不然不能正常工作,幸好cglib的網站已經提供了cglib和asm的綁定包,本文所用的是cglib-nodep-2.2_beta1版本。

        本章先對如何對接口進行打樁示例,下一章再對如何對接口進行打樁示例。

先看欲打樁接口代碼:

 

/************************************************************
 * Project Name: lhjTest
 * File Name   : CoolInterface.java
 * File Desc   : CoolInterface.java
 * Author      : Administrator
 * Create      : 2007-3-25
 * Modify:
 ***********************************************************/
package org.lhj.cool.junit;

/**
 * @author Administrator
 */
public interface CoolInterface
{
    String reverseString(String inputStr) throws NullPointerException;
}

 

該接口很簡單,只要一個reverString的方法。

下面看看欲測試類(使用了CoolInterface)的代碼:

 

/************************************************************
 * Project Name: lhjTest
 * File Name   : UseCoolInterface.java
 * File Desc   : UseCoolInterface.java
 * Author      : Administrator
 * Create      : 2007-3-25
 * Modify:
 ***********************************************************/
package org.lhj.cool.mock;

import org.lhj.cool.junit.CoolInterface;

/**
 * @author Administrator
 */
public class UseCoolInterface
{
    private CoolInterface cool;
    
    public void setCoolInterface(CoolInterface cool)
    {
        this.cool = cool;
    }
    
    public String reverseString(String inputStr) throws NullPointerException
    {
        return cool.reverseString(inputStr);
    }

}

 

這個類也很簡單,相當於一個adapter。

下面看看如何使用easymock進行接口的打樁:

 

/************************************************************
 * Project Name: lhjTest
 * File Name   : UseCoolInterfaceJTest.java
 * File Desc   : UseCoolInterfaceJTest.java
 * Author      : Administrator
 * Create      : 2007-3-25
 * Modify:
 ***********************************************************/
package org.lhj.cool.mock;

import junit.framework.TestCase;

import org.easymock.MockControl;
import org.lhj.cool.junit.CoolInterface;
import org.lhj.cool.mock.UseCoolInterface;

/**
 * @author Administrator
 */
public class UseCoolInterfaceJTest extends TestCase
{
    private UseCoolInterface testInterface;
    
    private MockControl ctrl;
    
    private CoolInterface cool;

    /* (non-Javadoc)
     * @see junit.framework.TestCase#setUp()
     */
    protected void setUp() throws Exception
    {
        super.setUp();
        
        ctrl = MockControl.createControl(CoolInterface.class);
        cool = (CoolInterface) ctrl.getMock();
        
        testInterface = new UseCoolInterface();
        testInterface.setCoolInterface(cool);
    }

    /* (non-Javadoc)
     * @see junit.framework.TestCase#tearDown()
     */
    protected void tearDown() throws Exception
    {
        super.tearDown();
    }

    /**
     * Test method for {@link org.lhj.cool.mock.UseCoolInterface#reverseString(java.lang.String)}.
     */
    public void testReverseString()
    {        
        ctrl.expectAndThrow(cool.reverseString(null), new NullPointerException());        
        ctrl.expectAndReturn(cool.reverseString(""), null);
        ctrl.expectAndReturn(cool.reverseString("AAaa"), "aaAA");
        ctrl.expectAndReturn(cool.reverseString("aaAA"), "AAaa");
        ctrl.replay();
        
        try
        {
            testInterface.reverseString(null);
            fail();
        }
        catch (NullPointerException e)
        {
            //donothing
        }
        assertNull(testInterface.reverseString(""));
        assertEquals("aaAA", testInterface.reverseString("AAaa"));
        assertEquals("AAaa", testInterface.reverseString("aaAA"));
        
        ctrl.verify();
    }
}

 

從上面可以看出使用easymock的步驟:

1、在setUp時創建MockControl,它是控制mock object行為的類,參數傳入欲打樁的接口的class。

2、從mockControl中getmock,返回mock object轉化為本類型對象。

3、創建欲測試類並將mock object傳進去。

以上幾步代碼為:

 

        ctrl = MockControl.createControl(CoolInterface.class);
        cool = (CoolInterface) ctrl.getMock();
        
        testInterface = new UseCoolInterface();
        testInterface.setCoolInterface(cool);

 

4、使用mockControl對mock object進行設置,這一步又稱為訓練,代碼為

 

        ctrl.expectAndThrow(cool.reverseString(null), new NullPointerException());        
        ctrl.expectAndReturn(cool.reverseString(""), null);
        ctrl.expectAndReturn(cool.reverseString("AAaa"), "aaAA");
        ctrl.expectAndReturn(cool.reverseString("aaAA"), "AAaa");

第一行意思是告訴mockControl,mock object的reverseString方法會被調用,傳入的參數是null,並會拋出異常;第二行意思是告訴mockControl,mock object的reverseString方法會被調用,傳入的參數是"",並返回null;其他行類似。

5、訓練完之后可以接受檢查了,代碼為:

 

        ctrl.replay();

 

6、現在可以進行測試了,以下是測試代碼:

        try
         {
            testInterface.reverseString(null);
            fail();
        }
        catch (NullPointerException e)
        {
            //donothing
        }
        assertNull(testInterface.reverseString(""));
        assertEquals("aaAA", testInterface.reverseString("AAaa"));
        assertEquals("AAaa", testInterface.reverseString("aaAA"));

可以看出,這跟一般的JUnit語句是一樣的。

7、檢驗測試結果

 

        ctrl.verify();

 

mockControl會驗證mockObject是否按照訓練的情況參與了測試,即訓練時的方法是否被調用了,傳入的參數對不對。

         以上示例只是easymock的一部分功能,除此之外,easymock還能測試mockObject的方法是否按照順序調用了,調用的次數對不對,傳入的參數是否在給定的范圍之內,另外還可以改變參數對象的內容。

        除了easymock可以mock接口外,像mock objects,Jmock,mock Creator都可以實現此類功能。其中mock Creator還可以mock class,但是可惜mock creator是靜態打樁的,實現起來有額外的工作。我在公司里用的是jdk1.4,無法用easymockclassextension1.2,所以使用了easymock加mock creator,幸好mock creator有eclipse插件,生成mock class也比較方便。所以如果你使用的是JDK1。4,用easymock加mock creator絕對是最佳組合;如果你使用的是JDK1.5,那么使用easymock加easymockclassextension會使你工作更輕松。

 
來自:http://blog.csdn.net/hardblackking/article/details/1544519


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM