JMockit是google code上面的一个java单元测试的mock框架。
对@Tested对象判断是否为null,是则通过合适构造器初始化, @Injectable的实例会自动注入到@Tested中。
@Mocked
@Mocked修饰的实例,将会把实例对应类的所有实例的所有行为都mock掉(无论构造方法,还是private,protected方法)。
Expectations
录制期望发生行为的块,一般由Expectations类和NonStrictExpectations类定义,用Expectations类定义的,则mock对象在运行时只能按照 Expectations块中定义的顺序依次调用方法,不能多调用也不能少调用,所以可以省略掉Verifications块;而用NonStrictExpectations类定义的,则没有这些限制,所以如果需要验证,则要添加Verifications块。result和times都是其内定成员变量。result可以重定义录制行为的返回值甚至通过Delegate来重定义行为,times是期待录制行为的发生次数。在Expectations中发生的调用,均会被mock。
Deencapsulation
用于Mock私有方法和私有属性。
简单示例:
JMockit涉及到的元素介绍:
@Tested和@Injectable对@Tested对象判断是否为null,是则通过合适构造器初始化, @Injectable的实例会自动注入到@Tested中。
@Mocked
@Mocked修饰的实例,将会把实例对应类的所有实例的所有行为都mock掉(无论构造方法,还是private,protected方法)。
Expectations
录制期望发生行为的块,一般由Expectations类和NonStrictExpectations类定义,用Expectations类定义的,则mock对象在运行时只能按照 Expectations块中定义的顺序依次调用方法,不能多调用也不能少调用,所以可以省略掉Verifications块;而用NonStrictExpectations类定义的,则没有这些限制,所以如果需要验证,则要添加Verifications块。result和times都是其内定成员变量。result可以重定义录制行为的返回值甚至通过Delegate来重定义行为,times是期待录制行为的发生次数。在Expectations中发生的调用,均会被mock。
Deencapsulation
用于Mock私有方法和私有属性。
简单示例:
package com.zero.jmockit;
public class Utils {
private static String URL_STRING = "http://www.sina.com.cn";
private static void deal() {
System.out.println("deal() " + URL_STRING);
}
public static String getObject(JMockitObject object, String str) {
deal();
System.out.println("getObject() ");
return URL_STRING + str;
}
}
package com.zero.jmockit;
public class UserService {
public String getUserName(int id) {
return "hello";
}
}
package com.zero.jmockit;
import javax.annotation.Resource;
public class JMockitObject {
@Resource
private UserService userService;
public void dealUser() {
String name = userService.getUserName(1);
System.out.println("userService.getUserName() : " + name);
sys(name);
}
private void sys(String name) {
System.out.println("sys() : " + name);
}
public String getString() {
getObject(this, "/zero");
return Utils.getObject(this, "/zero");
}
private void getObject(JMockitObject object, String str) {
System.out.println("--------");
}
}
package com.zero.jmockit;
import org.junit.*;
import org.junit.runner.RunWith;
import mockit.*;
import mockit.integration.junit4.JMockit;
@RunWith(JMockit.class)
public final class JMockitTest {
@Tested
@Mocked
private JMockitObject jMockitObject;
@Injectable
private UserService userService;
@Test
public void testDealUser() {
new NonStrictExpectations() {// 录制预期模拟行为
{
userService.getUserName(anyInt);//mock public方法
result = "zero";// 也可以使returns("zero");
times = 1;
Deencapsulation.invoke(jMockitObject, "sys", anyString);//mock private方法
// sys()无返回值,没定义result,则调用的结果返回空,故result = null; 可写可不写
result = null;
}
};
jMockitObject.dealUser();//回放
}
@Test
public void testSys() {
Deencapsulation.invoke(jMockitObject, "sys", "Hello World!");//测试private方法
}
@Test
public void testStaticField() {// mock 静态私有属性
new NonStrictExpectations(Utils.class) {
{
Deencapsulation.setField(Utils.class, "URL_STRING",
"www.baidu.com");
}
};
// 第二种方式:
// new MockUp<Utils>() {
// {
// // 修改静态私有属性
// Deencapsulation.setField(Utils.class, "URL_STRING",
// "www.baidu.com");
// }
// };
String str = Deencapsulation.getField(Utils.class, "URL_STRING");
Assert.assertEquals("www.baidu.com", str);
}
@Test
public void testStaticFunction() {// mock 静态私有方法
new MockUp<Utils>() {
@Mock
private void deal() {// 注意在MockUp中的方法除了不包含static关键字以外,其他都和被Mock的方法签名相同,并且使用@Mock标注
System.out.println("mock deal() ");
}
};
Deencapsulation.invoke(Utils.class, "deal");
}
@Test
public void testGetString() {
new NonStrictExpectations() {
{
Deencapsulation.invoke(jMockitObject, "getObject",
withAny(JMockitObject.class), withAny(String.class));// 不能使用any这样的参数,否则必须使用正确类型的参数;
// withAny(JMockitObject.class), anyString); 可以
}
};
new NonStrictExpectations(Utils.class) {
{
Utils.getObject((JMockitObject) any, anyString);
returns("zero");
}
};
Assert.assertEquals("zero", jMockitObject.getString());
}
}