??在編寫單元測試的時候,需要驗(yàn)證某些信息,或者是返回結(jié)果,或者是執(zhí)行流程。一個沒有任何結(jié)果驗(yàn)證的單元測試是沒有任何意義的。對于存在返回值的方法,可以通過對返回值進(jìn)行校驗(yàn)(使用Assert),來判斷方法的邏輯正確。但是對于返回值為void的方法,或者想要校驗(yàn)?zāi)承﹎ock的方法是否被調(diào)用,此時就需要使用Verify來進(jìn)行驗(yàn)證。
??Verifying功能非常強(qiáng)大,在Mockito、PowerMockito等框架中都存在相應(yīng)的方法。它可以檢查在單元用例執(zhí)行過程中某個方法是否被執(zhí)行,Powermock提供了多種方式驗(yàn)證方法是否被調(diào)用。
一、Verify普通方法
??先來看下業(yè)務(wù)代碼。
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();
}
}
??業(yè)務(wù)代碼很簡單,現(xiàn)在看下測試用例:
@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被調(diào)用
Mockito.verify(userMock).create();
// Verify方法update沒有被調(diào)用
Mockito.verify(userMock, Mockito.never()).update();
}
}
??此處saveUser方法是void的,可以驗(yàn)證兩個邏輯,根據(jù)isNew的返回值來verify是create被調(diào)用還是update被調(diào)用。在該單元測試用例中,isNew被mock返回值為true,所以后面驗(yàn)證create被調(diào)用,update方法沒有被調(diào)用。
二、Verify靜態(tài)方法
??現(xiàn)在再來看一個verify靜態(tài)方法的例子。業(yè)務(wù)代碼:
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;
}
}
}
??業(yè)務(wù)代碼是根據(jù)給定的百分比給員工漲工資,如果成功則返回true,否則出現(xiàn)異常時返回false。下面測試用例verify方法Employee.giveIncrementOf被調(diào)用。
@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現(xiàn)在需要驗(yàn)證靜態(tài)方法,然后后面跟著需要驗(yàn)證的靜態(tài)方法調(diào)用。
三、Verify方法調(diào)用順序
??有時候想要驗(yàn)證多個方法是按照一定的順序執(zhí)行,比如在測試UserService.saveuser方法時,想要確保user.isNew先被調(diào)用,然后是user.create或user.update方法被調(diào)用,測試用例可以如下實(shí)現(xiàn):
@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();
}
??從上面的用例中可以看出,想要驗(yàn)證方法的調(diào)用順序,需要以下兩點(diǎn):
??1. 首先創(chuàng)建一個InOrder實(shí)例;
??2. 使用這個實(shí)例按照給定的順序來驗(yàn)證相應(yīng)的方法。給定的方法的順序必須精確的匹配方法調(diào)用的順序,否則會執(zhí)行錯誤。
四、其他驗(yàn)證方法及模式
??Mockito和PowerMockito除了上述介紹的用法外,還提供了很多其他相關(guān)的verify方法。
//根據(jù)模式驗(yàn)證普通方法
public static <T> T verify(T mock, VerificationMode mode);
//根據(jù)模式驗(yàn)證靜態(tài)方法
public static synchronized void verifyStatic(VerificationMode verificationMode);
//驗(yàn)證一個實(shí)例的私有方法
public static PrivateMethodVerification verifyPrivate(Object object) throws Exception;
//根據(jù)模式驗(yàn)證一個實(shí)例的私有方法
public static PrivateMethodVerification verifyPrivate(Object object, VerificationMode verificationMode) throws Exception;
//驗(yàn)證一個類的私有方法
public static PrivateMethodVerification verifyPrivate(Class<?> clazz);
//根據(jù)模式驗(yàn)證一個類的私有方法
public static PrivateMethodVerification verifyPrivate(Class<?> clazz, VerificationMode verificationMode) throws Exception;
相關(guān)模式常用的有:
- Mockito.times(int n): 精確地驗(yàn)證執(zhí)行次數(shù)
- Mockito.atLeastOnce(): 驗(yàn)證方法至少被調(diào)用一次
- Mockito.atLeast(int n): 驗(yàn)證方法至少被執(zhí)行的次數(shù)
- Mockito.atMost(int n): 驗(yàn)證方法至多被執(zhí)行的次數(shù)