简介
Mockito的工作原理是通过创建依赖对象的proxy,所有的调用先经过proxy对象,proxy对象拦截了所有的请求再根据预设的返回值进行处理。Mockito虽然功能强大,但它不能mock静态方法、构造方法、私有方法以及 Final 方法。而很多时候这些方法也是需要测试的,因此PowerMock诞生了。PowerMock在Mockito原有的基础上做了扩展,通过修改类字节码并使用自定义ClassLoader加载运行的方式来实现mock静态方法、构造方法、final方法、private方法、系统类的功能。
在使用上,PowerMock与Mockito略有不同,首先是测试类上的@RunWith注解需要修改为:
@RunWith(PowerMockRunner.class)
第二是需要使用到@PrepareForTest注解(PrepareFotTest注解会修改传入参数类的字节码,通过修改字节码达到模拟final、static、私有方法、系统类等的功能),此注解可写在类上也可写在方法上:
@PrepareForTest({Apple.class, Singleton.class})
在使用PowerMock时,@RunWith(PowerMockRunner.class)和@PrepareForTest({**.class})必须要有,否则会报错:org.powermock.api.mockito.ClassNotPreparedException。
常用方法
首先我们定义一个Laptop类,Apple继承于它。其中有我们后面需要mock的static、private等方法。
public class Laptop {
private String cpu = "intel";
public String getCpu(){
System.out.println("getCpu");
return cpu;
}
}
public class Apple extends Laptop{
private static String TAG = Apple.class.getName();
public Apple() {
}
public static String getTAG(){
return TAG;
}
public static String getColor() {
System.out.println("getColor");
return "深灰色";
}
public String getAppleInfo() {
System.out.println("getAppleInfo");
return getFlavor() + getColor();
}
private String getFlavor() {
System.out.println("getFlavor");
return "快得很";
}
public final int getStorage() {
System.out.println("getStorage");
return 256;
}
}
mock静态方法
使用PowerMockito.mockStatic来mock静态方法:
@Test
@PrepareForTest({Apple.class})
public void testMockStatic() throws Exception {
PowerMockito.mockStatic(Apple.class);
PowerMockito.when(Apple.getColor()).thenReturn("红色");
String color = Apple.getColor();
Assert.assertEquals("红色", color);
}
除此之外,还可以修改静态变量,不过使用的是:
@Test
@PrepareForTest({Apple.class})
public void testChangeStatic() {
Whitebox.setInternalState(Apple.class, "TAG", "Mock");//指定静态变量“TAG”的值为“mock”
Assert.assertEquals("Apple", Apple.getTAG());//测试不通过
}
在实际开发中,我们还可以mock系统方法:
@Test
@PrepareForTest({Apple.class})
public void testMockSystem() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("123")).thenReturn("abc");
Assert.assertEquals("abc", System.getProperty("123"));
}
Mock私有方法
@Test
@PrepareForTest({Apple.class})
public void testMockPrivate() throws Exception {
Apple apple = PowerMockito.mock(Apple.class);
//调用实际方法,否则不会调用getFlavor()
PowerMockito.when(apple.getAppleInfo()).thenCallRealMethod();
//mock private方法
PowerMockito.when(apple, "getFlavor").thenReturn("快得很");
System.out.println(apple.getAppleInfo());
//验证getFlavor是否调用了一次
PowerMockito.verifyPrivate(apple, Mockito.times(1)).invoke("getFlavor");
}
在开发中,如果遇到不想让私有方法执行的情况,比如私有方法太耗时等,我们可以不执行私有方法:
@Test
@PrepareForTest({Apple.class})
public void testSkipPrivate() throws Exception {
Apple apple = new Apple();
PowerMockito.suppress(PowerMockito.method(Apple.class, "getFlavor"));
System.out.println(apple.getAppleInfo());
}
除此之外,PowerMock还提供了修改父类私有变量的方法:PowerMockito.field(declaringClass, fieldName).set(instance, value),或者使用MemberModifier类也可以,具体参考下面的代码:
@Test
@PrepareForTest({Apple.class})
public void testChangeFatherPrivate() throws Exception {
Apple apple = new Apple();
//更改父类私有变量
PowerMockito.field(Apple.class, "cpu").set(apple, "m1");
// MemberModifier.field(Apple.class, "cpu").set(apple, "m1");
Assert.assertEquals("m1", apple.getCpu());
}
@Test
@PrepareForTest({Apple.class})
public void testChangeFatherPrivate2() throws Exception {
Apple apple = PowerMockito.mock(Apple.class);
PowerMockito.when(apple.getCpu()).thenCallRealMethod();
//更改父类私有变量
PowerMockito.field(Apple.class, "cpu").set(apple, "m1");
// MemberModifier.field(Apple.class, "cpu").set(apple, "m1");
Assert.assertEquals("m1", apple.getCpu());
}
mock final方法
@Test
@PrepareForTest({Apple.class})
public void testMockFinal() {
Apple apple = PowerMockito.mock(Apple.class);
PowerMockito.when(apple.getStorage()).thenCallRealMethod();
PowerMockito.when(apple.getStorage()).thenReturn(128);
Assert.assertEquals(128, apple.getStorage());
}
mock构造方法
@Test
@PrepareForTest({Apple.class})
public void testMockConstructor() throws Exception {
Apple apple = PowerMockito.mock(Apple.class);
PowerMockito.when(apple.getStorage()).thenReturn(512);
PowerMockito.whenNew(Apple.class).withNoArguments().thenReturn(apple);
Apple apple1 = new Apple();
Assert.assertEquals(256, apple1.getStorage());
}
whenNew表示之后创建这个类的对象时,不再重新创建,而是直接返回某个被mock的对象。如果是有参数的构造方法,可以使用.withArguments()将参数传入,或者使用.withAnyArguments()。
mock单例类
首先定义一个单例类Singleton:
public class Singleton {
private static Singleton mInstance;
public static Singleton getInstance() {
if (mInstance == null) {
mInstance = new Singleton();
}
return mInstance;
}
private Singleton() {
}
private String serialNum;
public String getSerialNum() {
return serialNum;
}
}
测试用例:
@Test
@PrepareForTest({Singleton.class})
public void testMockSingleton() {
PowerMockito.mockStatic(Singleton.class);
Singleton mock = PowerMockito.mock(Singleton.class);
PowerMockito.when(Singleton.getInstance()).thenReturn(mock);
PowerMockito.when(mock.getSerialNum()).thenReturn("111");
Assert.assertEquals("111", mock.getSerialNum());
Singleton singleton = Singleton.getInstance();
Assert.assertEquals("111", singleton.getSerialNum());
Assert.assertEquals(mock.hashCode(), singleton.hashCode());
}
至此,有关Powermock的用法介绍完毕。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理