Android 单元测试 PowerMock框架的使用总结

在安卓中我们常用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框架的使用

你可能感兴趣的:(Android 单元测试 PowerMock框架的使用总结)