Android单元测试系列-Mock之PowerMock
Posted Chris_166
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android单元测试系列-Mock之PowerMock相关的知识,希望对你有一定的参考价值。
Android单元测试系列(3)-Mock之Mockito_Chris_166的博客-CSDN博客
Android单元测试系列(1)-开篇_Chris_166的博客-CSDN博客
这两篇中已经分别介绍过Mockito的使用和局限性,本篇将介绍PowerMock,用来扩展Mockito功能,弥补其局限性(Mockito不能mock private、static方法和类,一些版本不能mock final方法和类),同时PowerMock还增加了很多反射方法来修改静态和非静态成员等。
一、官网
https://github.com/powermock/powermock/wiki/Mockito
PowerMock是依赖Mockito的,所以使用时要同时引入,且版本也必须一一对应。
PowerMock跟Mockito的版本对应关系如下:
二、Demo示例
这里Demo按照Mockito 2.8.9,PowerMock 1.7.x来搭配。
// Gradle依赖
dependencies
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
testImplementation 'junit:junit:4.+'
testImplementation 'org.mockito:mockito-core:2.8.9'
testImplementation "org.powermock:powermock-api-mockito2:1.7.1" // 这个mockito2必须引入,否则的话会找不到PowerMockito类
testImplementation "org.powermock:powermock-module-junit4:1.7.1"
testImplementation 'org.powermock:powermock-core:1.7.1'
// androidTestImplementation 'androidx.test.ext:junit:1.1.3'
//androidTestImplementation "org.mockito:mockito-android:4.4.0"
// 被测试的代码
package com.fanff.unittestdemo.junitdemo;
public class Calculator
public int addExact(int x, int y)
return x + y;
public int subtractExact(int x, int y)
return x - y;
public int multiplyExact(int x, int y)
return x * y;
// TODO: zero case
public int intDivide(int x, int y)
if (y == 0)
return dealZeroCase();
else
return x / y;
private int dealZeroCase()
return 0;
// 测试代码
需求:测试intDivide()方法中是否有调用到dealZero()方法
package com.fanff.unittestdemo.mockdemo;
import com.fanff.unittestdemo.junitdemo.Calculator;
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.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Mockito.times;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Calculator.class)
public class CalculatorMockTest
@Test
public void testIntDivide()
Calculator calculator = Mockito.spy(Calculator.class);
calculator.intDivide(1, 0);
@Test
public void testPrivateIntDivideMethod() throws Exception
Calculator calculatorPowermockObj = PowerMockito.spy(new Calculator());
calculatorPowermockObj.intDivide(1, 0);
PowerMockito.verifyPrivate(calculatorPowermockObj, times(1)).invoke("dealZeroCase"); // Pass
这里说明几点:
1. @RunWith(PowerMockRunner.class) :这里使用的Runner是PowerMockRunner,这样就可以与Mokito兼容了,即Mokito里的方法在这里也都是可以正常使用的;
2. @PrepareForTest(Calculator.class):务必记得加上这个PrepareForTest的注解,否则进行verify测试的时候怎么测试都是pass的,如下没有写这个注解,verifyPrivate()怎么测试都是pass:
@RunWith(PowerMockRunner.class)
// @PrepareForTest(Calculator.class)
public class CalculatorMockTest
@Test
public void testPrivateIntDivideMethod() throws Exception
Calculator calculatorPowermockObj = PowerMockito.spy(new Calculator());
calculatorPowermockObj.intDivide(8, 8);
// 如下测试,预期应该是fail的,但是居然实际测试为pass,因为没有加注解@PrepareForTest(Calculator.class)
PowerMockito.verifyPrivate(calculatorPowermockObj, times(6)).invoke("dealZeroCase");
三、PowerMock常用的测试方法
主要来看看PowerMock相对Mockito扩展的几点:private、final、static.
1. Private
// 被测试的类
package com.fanff.unittestdemo.junitdemo;
import java.util.ArrayList;
import java.util.List;
/**
* 用来做Powermock的测试.
* 方法名/类定义/魔数都是为了简单随意写的,仅仅只是用来介绍每种mock手段而已
*/
public class Person
private String mName;
private final List<String> mAddressList = new ArrayList<>();
private School mInnerSchoolObj;
public Person(String name)
mName = name;
public void modifyName(String name)
System.out.println("[public fun]++setName enter, name = " + name);
modifyInnerName(name);
public String getName()
return mName;
public void addAddressList(String address)
mAddressList.add(address);
public void addInnerAddressList(String innerAddr)
mAddressList.add(innerAddr);
public List<String> getAllAddress()
return mAddressList;
public String getSchoolNo()
return mInnerSchoolObj.getNo();
public int getModifyInfoTimes(String info)
return getInnerModifyInfoTimes(info) + 2;
private int getInnerModifyInfoTimes(String info)
return 1;
private void modifyInnerName(String name)
mName = name;
System.out.println("[private fun]setInnerName enter, finally set name = " + mName);
public static class School
private String no;// 学号
public void setNo()
public String getNo()
return no;
1.1 私有变量
package com.fanff.unittestdemo.mockdemo;
import com.fanff.unittestdemo.junitdemo.Person;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.powermock.api.support.membermodification.MemberModifier;
import org.powermock.reflect.Whitebox;
import java.util.List;
public class PersonTest
private Person mPerson;
@Before
public void setUp() throws Exception
mPerson = new Person("Chris");
@After
public void tearDown() throws Exception
mPerson =null;
/**
* 访问私有成员
*/
@Test
public void testGetPrivateMemberValue()
/ 读取
String name = Whitebox.getInternalState(mPerson, "mName");
Assert.assertEquals("Chris", name);
mPerson.addAddressList("Wuhan");
mPerson.addAddressList("Shenzhen");
List<String> list = Whitebox.getInternalState(mPerson, "mAddressList");
Assert.assertEquals(2, list.size());
Assert.assertEquals("Shenzhen", list.get(list.size()-1));
/ 读取
/ 两种修改私有成员的方法
Whitebox.setInternalState(mPerson, "mName", "FanFF");
Assert.assertEquals("FanFF", mPerson.getName());
try
MemberModifier.field(Person.class, "mName").set(mPerson, "FanFF_166");
catch (Exception e)
Assert.assertEquals("FanFF_166", mPerson.getName());
/ 修改
1. 读取私有变量使用Whitebox.getInternalState()方法;
2. 修改私有变量,可以有如下两种方法:
(1) Whitebox.setInternalState()
(2) MemberModifier.field()
1.2 私有方法
package com.fanff.unittestdemo.mockdemo;
import com.fanff.unittestdemo.junitdemo.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Person.class)
public class PersonTest
/**
* 访问私有成员方法
*/
@Test
public void testPrivateMethod() throws Exception
/ Verify私有方法 //
Person personMockObj = PowerMockito.mock(Person.class);
personMockObj.getModifyInfoTimes("school");
PowerMockito.verifyPrivate(personMockObj, times(0)).invoke("getInnerModifyInfoTimes", anyString());
Person personSpyObj = PowerMockito.spy(new Person("Chris"));
personSpyObj.getModifyInfoTimes("school");
PowerMockito.verifyPrivate(personSpyObj, times(1)).invoke("getInnerModifyInfoTimes", anyString());
PowerMockito的Verify需要用@PrepareForTest之前已经说过了
2. Final
3. Static
//待续
以上是关于Android单元测试系列-Mock之PowerMock的主要内容,如果未能解决你的问题,请参考以下文章