背景:
今天使用powermock的时候同事说被mock的私有/公共方法一直报空指针异常,但是mock静态类并没有异常,觉得很奇怪,本文就来讲下powermock私有/公共方法和静态方法对于doReturn…when 和 when.thenReturn的不同表现,以及使用时的注意事项
追查真相
首先看下用来mock测试的私有方法和静态方法类,如下图所示:
public class MyPrivateMethod {
private String myPrivateFunc(Integer num){
String result = "private:" + num.toString();
return result;
}
public String myShow(Integer num){
return myPrivateFunc(num) + "_xxxxx";
}
}
public class MyStaticMethod {
public static String myStaticFunc(Long num) {
String result = "static:" + num.toString();
return result;
}
public String myDisplay(Long num) {
return myStaticFunc(num) + "_yyyyy";
}
}
其次是我们使用来测试的代码:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"})
@PrepareForTest({MyPrivateMethod.class, MyStaticMethod.class})
public class PowerMockTest {
/**
* 对于私有和共有方法的mock 1. when().thenReturn的方式会使用mock的参数调用被mock的方法,产生副作用,比如这里的空指针异常
*/
@Test
public void testPrivate0() throws Exception {
MyPrivateMethod inst = PowerMockito.spy(new MyPrivateMethod());
// 这种方式会使用Mockito.any()也就是null对象调用myPrivateFunc函数,此时就会产生空指针异常
PowerMockito.when(inst, "myPrivateFunc", Mockito.any()).thenReturn("mockPrivateResult");
Integer num = 100;
String ret = inst.myShow(num);
Assert.assertTrue(ret.equals("mockPrivateResult_xxxxx"));
}
/**
* 对于私有和共有方法的mock 1. doReturn().when不会产生额外的副作用,这其实才是真正我们想要的.
*/
@Test
public void testPrivate1() throws Exception {
MyPrivateMethod inst = PowerMockito.spy(new MyPrivateMethod());
// 这种方式不会实际调用myPrivateFunc方法,所以不会产生异常
PowerMockito.doReturn("mockPrivateResult").when(inst, "myPrivateFunc", Mockito.any());
Integer num = 100;
String ret = inst.myShow(num);
Assert.assertTrue(ret.equals("mockPrivateResult_xxxxx"));
}
/**
* 静态方法的mock
* 1.不论是使用when().thenReturn的方式还是doReturn.when的方式都不会产生副作用
* */
@Test
public void testStatic() throws Exception {
MyStaticMethod inst = PowerMockito.spy(new MyStaticMethod());
PowerMockito.mockStatic(MyStaticMethod.class);
PowerMockito.when(MyStaticMethod.myStaticFunc(Mockito.any())).thenReturn("myStaticFunc");
// PowerMockito.doReturn("myStaticFunc").when(MyStaticMethod.class, "myStaticFunc", Mockito.any());
Long num = 1000L;
String ret = inst.myDisplay(num);
Assert.assertTrue(ret.equals("myStaticFunc_yyyyy"));
}
}
对于mock私有和公共方法来说异常如下:
java.lang.NullPointerException
at org.example.pmock.MyPrivateMethod.myPrivateFunc(MyPrivateMethod.java:7)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.example.pmock.PowerMockTest.testPrivate0(PowerMockTest.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
由于对于mock私有和公共方法来说,when.doReturn会使用mock的参数实际调用被mock方法,虽然对于静态方法来说不会这样,但是为了统一,还是推荐mock方法是统一使用doReturn…when的方式来mock数据