1、引入的包
powermock-module-junit4
powermock-api-mockito2
javassist
mockito-core
2、常用的方法
2.1 方法名上注解
@RunWith(PowerMockRunner.class)
@PrepareForTest(Log.class)
// @PowerMockIgnore({"javax.management.*", "javax.script.*"}) 不要忽略报错
@SuppressStaticInitializationFor({ // 应该抑制 mock的对象静态属性和静态块的初始化
"com.sleepycat.je.SecondaryDatabase"})
2.2 mock类
PowerMockito.mockStatic(Log.class);
// mockstaic 静态类的方法 如果你doNothing 就不需要mock,默认就是 doNothing
// PowerMockito.doNothing().when(Log.class, PowerMockito.method(Log.class, "e", Exception.class)).withArguments(Mockito.any());
// 被测试类 正常属性值,可以直接set
queryPropertiesconfig = PowerMockito.mock(QueryPropertiesconfig.class);
testOwner.queryPropertiesQconfig = queryPropertiesQconfig;
2.3 mock 私有属性 https://blog.csdn.net/github_32521685/article/details/50556243
// BrandSetParam mock实例
MemberModifier.field(BrandSetParam.class, "brandSet").set(param, brandSet);
其他的 mock 静态私有 属性方法
PowerMockito.mockStatic(QueryUtils.class);
// Whitebox.setInternalState(QueryUtils.class, "brandsetcount", 10);
Field field = PowerMockito.field(QueryUtils.class, "brandsetcount");
field.setInt(null ,10);
2.4 Mock 私有方法(private method),返回特定值
MemberModifier.stub(MemberMatcher.method(PrivateObject .class, "getPrivateString")).toReturn( "Power Mock");
另外一种获取Method的方法
Method methodToEntity = PowerMockito.method(GetNewStoreProductService.class,
"toEntity",
String.class);
MemberModifier.stub(methodToEntity).toReturn(new ProductEntry() {{
setProductId(1);
}});
2.5 抑制父类的方法 和 替换父类的方法
作者:zyxing
链接:https://www.zhihu.com/question/58768289/answer/522121438
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
@RunWith(PowerMockRunner.class)
@PrepareForTest(Bar.class)
public class FooTest {
@Test
public void testBar() throws Exception {
Method method = PowerMockito.method(Bar.class, "bar");
// 抑制父类的这个方法执行
PowerMockito.suppress(method);
Foo foo = new Foo();
foo.bar();
}
@Test
public void testNumBar() throws Exception {
Method methodFoo = PowerMockito.method(Foo.class, "numBar");
// 替换掉父类的方法
PowerMockito.replace(methodFoo).with(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return 1;
}
});
Foo foo = new Foo();
int numBar = foo.numBar();
Assert.assertEquals(1, numBar);
}
}
2.6 测试被测对象的私有方法,使用反射
Method method = PowerMockito.method(TrafficInfoWrapperImpl.class, "getTrafficInfoEntity", HotelInfoType.class, TrafficInfoParameter.class);
TrafficInfoEntity positionInfo = (TrafficInfoEntity) method.invoke(trafficInfoWrappers, hotelInfoType, trafficInfoParameter);
2.7 mock被测试方法内部调用的方法
@spy和@mock的对象在使用when…thenReturn有区别:
@mock写法: cal中所有的方法都不是真实的且默认返回null,用mock去模拟返回值时sumXX方法会先执行一次,而因为执行的不是真实的方法所以并没有什么影响。
Calculator cal=PowerMockito.mock(Calculator.class);
PowerMockito.when(cal,“sumXX”,anyInt(),anyInt()).thenReturn(2);
assertEquals(2, cal.callSumXX(1, 2));
@spy写法: cal中所有的方法都是真实的,用when…thenReturn时就会去执行真实的私有方法,那么私有方法里面所有的代码都会执行一遍,这样是不可行的,因为很有可能私有方法就会依赖真实的环境。需要改用doReturn…when才会不执行真实的方法。
Calculator cal=PowerMockito.spy(new Calculator());
PowerMockito.doReturn(2).when(cal,“sumXX”,anyInt(),anyInt());
assertEquals(2, cal.callSumXX(1, 2));
public class Calculator {
private int sumXX(int a, int b) {
return a + b;
}
public int callSumXX(int a, int b) {
return sumXX(a, b);
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
public class CalculatorTest {
@Test
public void testSumXX() throws Exception {
Calculator cal = PowerMockito.mock(Calculator.class);
PowerMockito.when(cal,"sumXX",anyInt(),anyInt()).thenReturn(2);
//指明callSumXX调用真实的方法
PowerMockito.when(cal.callSumXX(anyInt(),anyInt())).thenCallRealMethod();
assertEquals(2, cal.callSumXX(1, 2));
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
public class CalculatorTest {
@Test
public void testSumXX() throws Exception {
Calculator cal = PowerMockito.spy(new Calculator());
PowerMockito.doReturn(2).when(cal,"sumXX",anyInt(),anyInt());
assertEquals(2, cal.callSumXX(1, 2));
}
}
还有一个问题 如果@spy mock的方法,是private 的会执行一次方法内部,public的方法不会执行,直接doReturn 返回值。如下,
SlaveRoomNameCollecter spy = Mockito.spy(underTest);
PowerMockito.doReturn("name").when(spy, "getNameByID", anyInt(), anyString());
2.8 被mock对象 调用自己真实的方法
Mockito.doCallRealMethod().when(operateDistrict).getAllByPrimaryKey(Mockito.any());
3、遇见的异常
java.lang.IllegalStateException: Failed to transform class with name XXXXXX
InterfaceMethodrefInfo cannot be cast to MethodrefInfo
解决办法:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>javassist</artifactId>
<groupId>org.javassist</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
参考 : http://www.javaear.com/question/31189086.html
3.2 Mock在前,new 被测试的类的实例 放在后后面,否则可能出现 new 的时候就依赖了 mock的数据,比如有 静态代码块
3.3 mock 任意值 和 特定值 混搭
// 被 mock方法
public static Integer getDefaultInt(String key,Integer defaultValue) {//}
// correct
PowerMockito.when(SystemInfo.getDefaultInt(Mockito.anyString(), Mockito.anyInt())).thenReturn(3);
// correct
PowerMockito.when(SystemInfo.getDefaultInt("sort.change.day", 2)).thenReturn(3);
// incorrect 不能任意值 和 特定值 混搭
PowerMockito.when(SystemInfo.getDefaultInt(Mockito.anyString(), 2)).thenReturn(3);
对应的报错信息
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at com.ctrip.hotel.search.das.mlstoreproduct.datafilter.MlstoreproductDataFilterTest.testParseDasEntity(MlstoreproductDataFilterTest.java:57)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
4、InjectMocks 和 Mock
@InjectMocks:创建一个实例,简单的说是这个Mock可以调用真实代码的方法,其余用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。
@Mock:对函数的调用均执行mock(即虚假函数),不执行真正部分。
@Spy:对函数的调用均执行真正部分。
Mockito中的Mock和Spy都可用于拦截那些尚未实现或不期望被真实调用的对象和方法,并为其设置自定义行为。二者的区别在于Mock不真实调用,Spy会真实调用。
@InjectMocks
private HotFeatureRepositoryImpl repository;
@Mock
private GetProvinceFilterClient<List<HotSearchKeywordStatModel>> getProvinceFilterClient;
@Test
public void getHotFeaturesByProvinceAsync_Invalid() {
repository.getHotFeaturesByProvinceAsync(0);
}
注意事项:
InjectMocks 被测试类如果有父类,并且会有一些静态属性初始化的话,会在@before前执行,所以可能会出现NPE等错误。