在编写单元测试的时候,需要验证某些信息,或者是返回结果,或者是执行流程。一个没有任何结果验证的单元测试是没有任何意义的。对于存在返回值的方法,可以通过对返回值进行校验(使用Assert),来判断方法的逻辑正确。但是对于返回值为void的方法,或者想要校验某些mock的方法是否被调用,此时就需要使用Verify来进行验证。
Verifying功能非常强大,在Mockito、PowerMockito等框架中都存在相应的方法。它可以检查在单元用例执行过程中某个方法是否被执行,Powermock提供了多种方式验证方法是否被调用。
一、Verify普通方法
先来看下业务代码。
public class User {
public boolean isNew() {
throw new UnsupportedOperationException();
}
public void update() {
throw new UnsupportedOperationException();
}
public void create() {
throw new UnsupportedOperationException();
}
}
public class UserService {
public void saveUser(User user) {
if (user.isNew()) {
user.create();
return;
}
user.update();
}
}
业务代码很简单,现在看下测试用例:
@RunWith(PowerMockRunner.class)
public class UserServiceTest {
@Mock
private User userMock;
@Test
public void shouldCreateUserIfUserIsNew() {
PowerMockito.when(userMock.isNew()).thenReturn(true);
UserService userService = new UserService();
userService.saveUser(userMock);
// Verify方法create被调用
Mockito.verify(userMock).create();
// Verify方法update没有被调用
Mockito.verify(userMock, Mockito.never()).update();
}
}
此处saveUser方法是void的,可以验证两个逻辑,根据isNew的返回值来verify是create被调用还是update被调用。在该单元测试用例中,isNew被mock返回值为true,所以后面验证create被调用,update方法没有被调用。
二、Verify静态方法
现在再来看一个verify静态方法的例子。业务代码:
public class Employee {
public static void giveIncrementOf(int percentage) {
throw new UnsupportedOperationException();
}
}
public class EmployeeService {
public boolean giveIncrementToAllEmployeeOf(int percentage) {
try {
Employee.giveIncrementOf(percentage);
return true;
} catch (Exception e) {
return false;
}
}
}
业务代码是根据给定的百分比给员工涨工资,如果成功则返回true,否则出现异常时返回false。下面测试用例verify方法Employee.giveIncrementOf被调用。
@RunWith(PowerMockRunner.class)
@PrepareForTest({Employee.class})
public class EmployeeServiceTest {
@Test
public void shouldInvokeGiveIncrementOfMethod() {
// Mock
PowerMockito.mockStatic(Employee.class);
PowerMockito.doNothing().when(Employee.class);
Employee.giveIncrementOf(9);
// Execute
EmployeeService employeeService = new EmployeeService();
employeeService.giveIncrementToAllEmployeeOf(9);
// Verify
PowerMockito.verifyStatic();
Employee.giveIncrementOf(9);
}
}
首先使用verifyStatic通知Powermock现在需要验证静态方法,然后后面跟着需要验证的静态方法调用。
三、Verify方法调用顺序
有时候想要验证多个方法是按照一定的顺序执行,比如在测试UserService.saveuser方法时,想要确保user.isNew先被调用,然后是user.create或user.update方法被调用,测试用例可以如下实现:
@Test
public void shouldInvokeIsNewBeforeInvokingUpdate() {
UserService userService = new UserService();
userService.saveUser(userMock);
InOrder inOrder = Mockito.inOrder(userMock);
inOrder.verify(userMock).isNew();
inOrder.verify(userMock).update();
inOrder.verify(userMock, Mockito.never()).create();
}
从上面的用例中可以看出,想要验证方法的调用顺序,需要以下两点:
1. 首先创建一个InOrder实例;
2. 使用这个实例按照给定的顺序来验证相应的方法。给定的方法的顺序必须精确的匹配方法调用的顺序,否则会执行错误。
四、其他验证方法及模式
Mockito和PowerMockito除了上述介绍的用法外,还提供了很多其他相关的verify方法。
//根据模式验证普通方法
public static T verify(T mock, VerificationMode mode);
//根据模式验证静态方法
public static synchronized void verifyStatic(VerificationMode verificationMode);
//验证一个实例的私有方法
public static PrivateMethodVerification verifyPrivate(Object object) throws Exception;
//根据模式验证一个实例的私有方法
public static PrivateMethodVerification verifyPrivate(Object object, VerificationMode verificationMode) throws Exception;
//验证一个类的私有方法
public static PrivateMethodVerification verifyPrivate(Class> clazz);
//根据模式验证一个类的私有方法
public static PrivateMethodVerification verifyPrivate(Class> clazz, VerificationMode verificationMode) throws Exception;
相关模式常用的有:
- Mockito.times(int n): 精确地验证执行次数
- Mockito.atLeastOnce(): 验证方法至少被调用一次
- Mockito.atLeast(int n): 验证方法至少被执行的次数
- Mockito.atMost(int n): 验证方法至多被执行的次数