背景
代码设计并不总是尽善尽美,有些单元测试是Mockito力不从心的。
这时候就需要PowerMock ,这个框架是对Mockito增强。
下面展示几个常用场景
- mock静态方法
- 跳过私有方法
- 更改子类无法访问的父类私有field
- 更改类的私有static常量
- 模拟New构造函数
示例
首先引入Maven依赖
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
要测试的业务类包含了几个特殊用例
abstract class MyParent {
private String parentValue = "parent";
private String getMessageContent() {
return parentValue;
}
protected String getParentMessage() {
return getMessageContent();
}
}
public class Mytest extends MyParent {
private static String BID = "999";
public Mytest() {
}
public static String getBid() {
return BID;
}
public static String getMessage() {
return "hello";
}
public String sendEmail() {
String response = "send email";
System.out.println(response);
response = sendMessage("success");
return response;
}
private String sendMessage(String status) {
System.out.println("send message " + status);
return "send message " + status;
}
}
编写单元测试
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.api.support.membermodification.MemberModifier;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
@RunWith(PowerMockRunner.class) //以PowerMock启动Junit test
@PrepareForTest({Mytest.class}) //预处理要mock的类,在字节码的级别更改类的行为
public class Testmethod {
@Test
public void testStaticMethod() {//mock静态方法
PowerMockito.mockStatic(Mytest.class);
Mockito.when(Mytest.getMessage()).thenReturn("world");
Assert.assertEquals("world", Mytest.getMessage());
}
@Test
public void skipPrivateMethod() {//跳过私有方法
Mytest t = new Mytest();
PowerMockito.suppress(PowerMockito.method(Mytest.class, "sendMessage", String.class)); //类,方法名,参数类
String response = t.sendEmail();
Assert.assertTrue(response == null);//跳过了sendMessage方法,返回为null
}
@Test
public void changeParentPrivate() {//更改子类无法访问的父类私有field
Mytest t = new Mytest();
try {
MemberModifier.field(Mytest.class, "parentValue").set(
t, "tomcat");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Assert.assertEquals("tomcat", t.getParentMessage());//父类私有field已经被更改
}
@Test
public void changeBid() {//更改类的私有static常量
Whitebox.setInternalState(Mytest.class, "BID", "888");
Assert.assertEquals("888", Mytest.getBid());
}
@Test
public void mockNew() throws Exception {//模拟New构造方法
Mytest test = Mockito.mock(Mytest.class);
Mockito.when(test.getParentMessage()).thenReturn("hello");
PowerMockito.whenNew(Mytest.class).withNoArguments().thenReturn(test);
Mytest testNew = new Mytest();
Assert.assertEquals("hello", testNew.getParentMessage());
}
}
已知问题
PowerMock实现了自己的类加载器,占用内存大,容易造成内存不足:OutOfMemoryError