天道不一定酬所有勤
但是,天道只酬勤

[轉]使用JMockit編寫java單元測試

JMockit是基于JavaSE5中的java.lang.instrument包開發,內部使用ASM庫來動態修改java的字節碼,使得java這種靜態語言可以想動態腳本語言一樣動態設置被Mock對象私有屬性,模擬靜態、私有方法行為等等,對于手機開發,嵌入式開發等要求代碼盡量簡潔的情況下,或者對于被測試代碼不想做任何修改的前提下,使用JMockit可以輕松搞定很多測試場景。

20140104100723093

通過如下方式在maven中添加JMockit的相關依賴:

        <dependency>  
            <groupId>com.googlecode.jmockit</groupId>  
            <artifactId>jmockit</artifactId>  
            <version>1.5</version>  
            <scope>test</scope>  
        </dependency>  
        <dependency>  
            <groupId>com.googlecode.jmockit</groupId>  
            <artifactId>jmockit-coverage</artifactId>  
            <version>0.999.24</version>  
            <scope>test</scope>  
        </dependency>

JMockit有兩種Mock方式:基于行為的Mock方式和基于狀態的Mock方式:

引用單元測試中mock的使用及mock神器jmockit實踐中JMockit API和工具如下:

20140104102342843

(1).基于行為的Mock方式:

非常類似與EasyMock和PowerMock的工作原理,基本步驟為:

1.錄制方法預期行為。

2.真實調用。

3.驗證錄制的行為被調用。

通過一個簡單的例子來介紹JMockit的基本流程:

要Mock測試的方法如下:

public class MyObject {
    public String hello(String name){
        return "Hello " + name;
    }
}

使用JMockit編寫的單元測試如下:

@Mocked  //用@Mocked標注的對象,不需要賦值,jmockit自動mock  
MyObject obj;  

@Test  
public void testHello() {  
    new NonStrictExpectations() {//錄制預期模擬行為  
        {  
            obj.hello("Zhangsan");  
            returns("Hello Zhangsan");  
            //也可以使用:result = "Hello Zhangsan";  
        }  
    };  
    assertEquals("Hello Zhangsan", obj.hello("Zhangsan"));//調用測試方法  
    new Verifications() {//驗證預期Mock行為被調用  
        {  
            obj.hello("Hello Zhangsan");  
            times = 1;  
        }  
    };  
}  

JMockit也可以分類為非局部模擬與局部模擬,區分在于Expectations塊是否有參數,有參數的是局部模擬,反之是非局部模擬。

而Expectations塊一般由Expectations類和NonStrictExpectations類定義,類似于EasyMock和PowerMock中的Strict Mock和一般性Mock。

用Expectations類定義的,則mock對象在運行時只能按照 Expectations塊中定義的順序依次調用方法,不能多調用也不能少調用,所以可以省略掉Verifications塊;

而用NonStrictExpectations類定義的,則沒有這些限制,所以如果需要驗證,則要添加Verifications塊。

上述的例子使用了非局部模擬,下面我們使用局部模擬來改寫上面的測試,代碼如下:

@Test  
public void testHello() {  
    final MyObject obj = new MyObject();  
    new NonStrictExpectations(obj) {//錄制預期模擬行為  
        {  
            obj.hello("Zhangsan");  
            returns("Hello Zhangsan");  
            //也可以使用:result = "Hello Zhangsan";  
        }  
    };  
    assertEquals("Hello Zhangsan", obj.hello("Zhangsan"));//調用測試方法  
    new Verifications() {//驗證預期Mock行為被調用  
        {  
            obj.hello("Hello Zhangsan");  
            times = 1;  
        }  
    };  
}  

模擬靜態方法:

@Test  
public void testMockStaticMethod() {  
    new NonStrictExpectations(ClassMocked.class) {  
        {  
            ClassMocked.getDouble(1);//也可以使用參數匹配:ClassMocked.getDouble(anyDouble);  
            result = 3;  
        }  
    };  

    assertEquals(3, ClassMocked.getDouble(1));  

    new Verifications() {  
        {  
            ClassMocked.getDouble(1);  
            times = 1;  
        }  
    };  
}  

模擬私有方法:

如果ClassMocked類中的getTripleString(int)方法指定調用一個私有的multiply3(int)的方法,我們可以使用如下方式來Mock:

@Test  
public void testMockPrivateMethod() throws Exception {  
    final ClassMocked obj = new ClassMocked();  
    new NonStrictExpectations(obj) {  
        {  
            this.invoke(obj, "multiply3", 1);//如果私有方法是靜態的,可以使用:this.invoke(null, "multiply3")  
            result = 4;  
        }  
    };  

    String actual = obj.getTripleString(1);  
    assertEquals("4", actual);  

    new Verifications() {  
        {  
            this.invoke(obj, "multiply3", 1);  
            times = 1;  
        }  
    };  
}  

設置Mock對象私有屬性的值: 我們知道EasyMock和PowerMock的Mock對象是通過JDK/CGLIB動態代理實現的,本質上是類的繼承或者接口的實現,但是在java面向對象編程中,基類對象中的私有屬性是無法被子類繼承的,所以如果被Mock對象的方法中使用到了其自身的私有屬性,并且這些私有屬性沒有提供對象訪問方法,則使用傳統的Mock方法是無法進行測試的,JMockit提供了設置Mocked對象私有屬性值的方法,代碼如下: 被測試代碼:

public class ClassMocked {  
    private String name = "name_init";  

    public String getName() {  
        return name;  
    }  

    private static String className="Class3Mocked_init";  

    public static String getClassName(){  
        return className;  
    }  
}  

使用JMockit設置私有屬性:

@Test  
public void testMockPrivateProperty() throws IOException {  
    final ClassMocked obj = new ClassMocked();  
    new NonStrictExpectations(obj) {  
        {  
            this.setField(obj, "name", "name has bean change!");  
        }  
    };  

    assertEquals("name has bean change!", obj.getName());  
}  

使用JMockit設置靜態私有屬性:

@Test  
public void testMockPrivateStaticProperty() throws IOException {  
    new NonStrictExpectations(Class3Mocked.class) {  
        {  
            this.setField(ClassMocked.class, "className", "className has bean change!");  
        }  
    };  

    assertEquals("className has bean change!", ClassMocked.getClassName());  
}  

(2).基于狀態的Mock方式:

JMockit上面的基于行為Mock方式和傳統的EasyMock和PowerMock流程基本類似,相當于把被模擬的方法當作黑盒來處理,而JMockit的基于狀態的Mock可以直接改寫被模擬方法的內部邏輯,更像是真正意義上的白盒測試,下面通過簡單例子介紹JMockit基于狀態的Mock。 被測試的代碼如下:

public class StateMocked {  

    public static int getDouble(int i){  
        return i*2;  
    }  

    public int getTriple(int i){  
        return i*3;  
    }  
} 

改寫普通方法內容:

@Test  
public void testMockNormalMethodContent() throws IOException {  
    StateMocked obj = new StateMocked();  
    new MockUp<StateMocked>() {//使用MockUp修改被測試方法內部邏輯  
        @Mock  
      public int getTriple(int i) {  
            return i * 30;  
        }  
    };  
    assertEquals(30, obj.getTriple(1));  
    assertEquals(60, obj.getTriple(2));  
    Mockit.tearDownMocks();//注意:在JMockit1.5之后已經沒有Mockit這個類,使用MockUp代替,mockUp和tearDown方法在MockUp類中  
}  

修改靜態方法的內容: 基于狀態的JMockit改寫靜態/final方法內容和測試普通方法沒有什么區別,需要注意的是在MockUp中的方法除了不包含static關鍵字以外,其他都和被Mock的方法簽名相同,并且使用@Mock標注,測試代碼如下:

@Test  
    public void testGetTriple() {  
        new MockUp<StateMocked>() {  
            @Mock    
            public int getDouble(int i){    
                return i*20;    
            }  
        };    
        assertEquals(20, StateMocked.getDouble(1));    
        assertEquals(40, StateMocked.getDouble(2));   
    }  

原文鏈接: http://blog.csdn.net/chjttony/article/details/17838693

(全文完) 歡迎關注『Java之道』微信公眾號
贊(1)
如未加特殊說明,此網站文章均為原創,轉載必須注明出處。HollisChuang's Blog » [轉]使用JMockit編寫java單元測試
分享到: 更多 (0)

評論 搶沙發

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址

HollisChuang's Blog

聯系我關于我
网上设计赚钱的网站有哪些