在安卓中我们常用Junit + Mockito + PowerMock 组合进行测试。PowerMock是拓展Mockito,主要是为了解决Mockito 框架不支持mock匿名类、final类、static方法、private方法的问题,PowerMock内部调用了Mockito的方法(如:PowerMockito.when()内部调用的是Mockito.when())。
PowerMock的导入
testImplementation "org.powermock:powermock-module-junit4:1.7.3"
testImplementation "org.powermock:powermock-module-junit4-rule:1.7.3"
testImplementation "org.powermock:powermock-api-mockito2:1.7.3" //注意这里是mockito2
testImplementation "org.powermock:powermock-classloading-xstream:1.7.3"
PowerMock使用
首先我们定义一个Fruit类,Banana继承于它。其中有我们后面需要mock的static、private等方法。
abstract class Fruit {
private String fruit = "水果";
public String getFruit() {
return fruit;
}
}
public class Banana extends Fruit {
private static String COLOR = "黄色的";
private static String SIZE = "BIG";
private String place = "here";
public Banana() {}
public String getPlace() {
return place;
}
public static final String getColor() {
return COLOR;
}
private static String getSize() {
return SIZE;
}
public String getBananaInfo() {
return flavor() + getColor();
}
private String flavor() {
return "甜甜的";
}
public final boolean isLike() {
return true;
}
private final String getPrice() {
return "10";
}
public String privateFinal() {
return getPrice();
}
}
定义Mock类,:
方法一:
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
public class PowerMockito {
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
}
}
首先使用PowerMock必须在类名上加注@RunWith(PowerMockRunner.class),在方法上添加注解@PrepareForTest,注解@PrepareForTest里写的是要mock的方法所在的类。@PowerMockIgnore用于忽略mock的类,"android.*" 忽略android的相关类,因为我们使用Robolectric处理了;"org.mockito.*","org.robolectric.*" 忽略Mockito和Robolectric的相关类,因为我们不应该mock它们自己。
方法二:
有时我们会使用多个测试框架,可能@RunWith会占用,这时我们可以使用@Rule
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
public class PowerMockito {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
}
}
使用方法总结,(final)表示final可有可无:
1、Mock public (final):
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
Banana mBanana = PowerMockito.mock(Banana.class);
PowerMockito.when(mBanana.isLike()).thenReturn(false);
Assert.assertFalse(mBanana.isLike());
}
2、Mock public static (final):
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
PowerMockito.mockStatic(Banana.class);
PowerMockito.when(Banana.getColor()).thenReturn("green");
Assert.assertEquals("green", Banana.getColor());
}
3、Mock private (final):
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
Banana banana = PowerMockito.mock(Banana.class);
PowerMockito.when(banana.getBananaInfo()).thenCallRealMethod();
PowerMockito.when(banana, "flavor").thenReturn("苦苦的");
Assert.assertEquals("苦苦的黄色的", banana.getBananaInfo());
}
4、Mock private static (final): 无法模拟
5、更改类的私有static常量,不能是final:
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
Whitebox.setInternalState(Banana.class, "COLOR", "red");
Assert.assertEquals("red", Banana.getColor());
}
6、跳过私有方法:
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
PowerMockito.suppress(PowerMockito.method(Banana.class, "flavor"));
Assert.assertEquals("null黄色的", mBanana.getBananaInfo());
}
7、更改父类私有变量,不能是final:
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
Banana mBanana = new Banana();
MemberModifier.field(Banana.class, "fruit").set(mBanana, "蔬菜");
Assert.assertEquals("蔬菜", mBanana.getFruit());
}
8、Mock 构造方法:
@Test
@PrepareForTest({Banana.class})
public void testMethod() throws Exception {
Banana mBanana = PowerMockito.mock(Banana.class);
PowerMockito.when(mBanana.getBananaInfo()).thenReturn("大香蕉");
//如果new新对象,则返回这个上面设置的这个对象
PowerMockito.whenNew(Banana.class).withNoArguments().thenReturn(mBanana);
//new新的对象
Banana newBanana = new Banana();
Assert.assertEquals("大香蕉", newBanana.getBananaInfo());
}
参考文章:
Android单元测试(三):PowerMock框架的使用