PowerMock
特点
PowerMock是一个扩展了其它如EasyMock等mock框架的、功能更加强大的框架。PowerMock使用一个自定义类加载器和字节码操作来模拟静态方法、构造方法、final类和方法、私有方法、去除静态初始化器等等。
注解
@RunWith注解:powerMock
@PrepareForTest: 静态
@Mock:Mock注解创建了一个全部Mock的实例,所有属性和方法全被置空(0或者null)
@Spy:Spy注解创建了一个没有Mock的实例,所有成员方法都会按照原方法的逻辑执行,直到被Mock返回某个具体的值为止。
注意:@Spy注解的变量需要被初始化,否则执行时会抛出异常
@InjectMocks:InjectMocks注解创建一个实例,这个实例可以调用真实代码的方法,其余用@Mock或@Spy注解创建的实例将被注入到用该实例中。
@Captor:Captor注解在字段级别创建参数捕获器。但是,在测试方法启动前,必须调用MockitoAnnotations.openMocks(this)进行初始化
@PowerMockIgnore注解
为了解决使用PowerMock后,提示ClassLoader错误。
使用
Final
当模拟final类或final方法时,需要使用这两个注解@RunWith和@PrepareForTest注解
@RunWith(PowerMockRunner.class)
@PrepareForTest({TargetClass.class})
Circle circle = PowerMockito.mock(Circle.class);
复制代码
Static
必须使用“@RunWith”和“@PrepareForTest”注解
PowerMockito.mockStatic(Class clazz);
复制代码
Spy
模拟类的部分方法
我们只希望模拟它的部分方法,而希望其它方法跟原来一样,可以使用PowerMockito.spy方法代替PowerMockito.mock方法。于是,通过when语句设置过的方法,调用的是模拟方法;而没有通过when语句设置的方法,调用的是原有方法。
PowerMockito.spy(Class clazz);
复制代码
模拟对象的部分方法
T PowerMockito.spy(T object);
复制代码
When语句
when().thenReturn()模式
用于模拟对象方法,先执行原始方法,再返回期望的值、异常、应答,或调用真实的方法。
// 返回期望值
PowerMockito.when(mockObject.someMethod(someArgs)).thenReturn(expectedValue);
// 返回期望异常
PowerMockito.when(mockObject.someMethod(someArgs)).thenThrow(expectedThrowable);
// 期望应答
PowerMockito.when(mockObject.someMethod(someArgs)).thenAnswer(expectedAnswer);
// 调用原方法
PowerMockito.when(mockObject.someMethod(someArgs)).thenCallRealMethod();
复制代码
doReturn().when()模式
用于模拟对象方法,在SPY实例下:直接返回期望的值、异常、应答,或调用真实的方法,无需执行原始方法。
PowerMockito.doReturn(expectedValue).when(mockObject).someMethod(someArgs);
PowerMockito.doThrow(expectedThrowable).when(mockObject).someMethod(someArgs);
PowerMockito.doAnswer(expectedAnswer).when(mockObject).someMethod(someArgs);
PowerMockito.doNothing().when(mockObject).someMethod(someArgs);
PowerMockito.doCallRealMethod().when(mockObject).someMethod(someArgs);
复制代码
whenNew模拟构造方法
PowerMockito.whenNew(MockClass.class).withNoArguments().thenReturn(expectedObject);
PowerMockito.whenNew(MockClass.class).withArguments(someArgs).thenReturn(expectedObject);
复制代码
参数匹配器
任意值
Mockito提供Mockito.anyInt()、Mockito.anyString、Mockito.any(Class clazz)等来表示任意值。
参数匹配
当我们使用参数匹配器时,所有参数都应使用匹配器。如果要为某一参数指定特定值时,就需要使用Mockito.eq()方法。
符加匹配器
Mockito的AdditionalMatchers类提供了一些很少使用的参数匹配器,我们可以进行参数大于(gt)、小于(lt)、大于等于(geq)、小于等于(leq)等比较操作,也可以进行参数与(and)、或(or)、非(not)等逻辑计算等。
verify语句
验证是确认在模拟过程中,被测试方法是否已按预期方式与其任何依赖方法进行了交互。
用于模拟对象方法,直接返回期望的值、异常、应答,或调用真实的方法,无需执行原始方法。
Mockito.verify(mockObject[,times(int)]).someMethod(somgArgs);
复制代码
验证方法调用
mockList.clear();
Mockito.verify(mockList).clear();
复制代码
验证方法调用次数
timess、atLeastOnce、atLeast、only、atMostOnce、atMost等次数验证器。
mockList.clear();
Mockito.verify(mockList, Mockito.times(1)).clear();
复制代码
验证调用顺序
InOrder inOrder = Mockito.inOrder(mockedList);
inOrder.verify(mockedList).add(1);
inOrder.verify(mockedList).add(2);
inOrder.verify(mockedList).add(3);
复制代码
验证调用参数
ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor.forClass(Integer.class);
Mockito.verify(mockedList, Mockito.times(3)).add(argumentCaptor.capture());
复制代码
确保验证完毕
Mockito提供Mockito.verifyNoMoreInteractions方法,在所有验证方法之后可以使用此方法,以确保所有调用都得到验证。如果模拟对象上存在任何未验证的调用,将会抛出NoInteractionsWanted异常。
验证静态方法
PowerMockito.verifyStatic(StringUtils.class);
复制代码
私有属性
ReflectionTestUtils.setField方法设置私有属性值。
ReflectionTestUtils.setField(userService, "userLimit", expected);
复制代码
可以采用Whitebox.setInternalState方法设置私有属性
Whitebox.setInternalState(userService, "userLimit", expected);
复制代码
私有方法
通过模拟方法stub(存根),也可以实现模拟私有方法。但是,只能模拟整个方法的返回值,而不能模拟指定参数的返回值。
PowerMockito.stub(PowerMockito.method(UserService.class, "isSuperUser", Long.class)).toReturn(!expected);
复制代码
测试
Method method = PowerMockito.method(UserService.class, "isSuperUser", Long.class);
Object actual = method.invoke(userService, userId);
复制代码
验证
PowerMockito.verifyPrivate(userService).invoke("isSuperUser", userId);
复制代码