??在mock方法時(shí),對(duì)于方法的參數(shù)匹配是有要求的,只有要執(zhí)行的方法的參數(shù)匹配mock方法里面的參數(shù)時(shí),該mock方法才會(huì)起作用。Powermock提供了很多種參數(shù)匹配的方式,比如,如果需要精確地匹配參數(shù),可以使用equal方式;如果需要靈活地匹配參數(shù),可以使用any方式。下面,我們就來簡單地介紹下mock方法時(shí)的參數(shù)匹配。
一、精確匹配
??還是先來看下被測試代碼:
public class EmployeeService {
public Employee findEmployeeByEmail(String email) {
throw new UnsupportedOperationException();
}
public boolean employeeExists(Employee employee) {
throw new UnsupportedOperationException();
}
}
public class EmployeeController {
private EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
public Employee findEmployeeByEmail(String email) {
return employeeService.findEmployeeByEmail(email);
}
public boolean isEmployeeEmailAlreadyTaken(String email) {
return employeeService.employeeExists(new Employee(email));
}
}
??代碼很直觀,EmployeeController類中定義了兩個(gè)方法,一個(gè)是findEmployeeByEmail,根據(jù)email查詢員工,調(diào)用employeeService.findEmployeeByEmail方法;另一個(gè)方法是isEmployeeEmailAlreadyTaken方法,判斷某個(gè)員工是否存在,調(diào)用employeeService.employeeExists方法。
??
??現(xiàn)在看下測試代碼:
public class EmployeeControllerTest {
@Test
public void testFindEmployeeByEmail() {
EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
Employee employee = new Employee();
PowerMockito.when(employeeService.findEmployeeByEmail(Mockito.eq("123@abc.com"))).thenReturn(employee);
EmployeeController employeeController = new EmployeeController(employeeService);
Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@abc.com"));
Assert.assertNull(employeeController.findEmployeeByEmail("123@dce.com"));
}
}
??從上述測試方法可以看到,在模擬employeeService.findEmployeeByEmail方法時(shí)使用了eq方法,這個(gè)就是精確匹配模式,執(zhí)行參數(shù)完全匹配該參數(shù)時(shí),才會(huì)返回employee。
二、模糊匹配
??有時(shí)候,我們想要在匹配參數(shù)時(shí)更靈活些,可以使用模糊匹配??聪孪旅娴臏y試方法:
public class EmployeeControllerTest {
@Test
public void testFindEmployeeByEmail() {
EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
Employee employee = new Employee();
PowerMockito.when(employeeService.findEmployeeByEmail(Mockito.startsWith("123"))).thenReturn(employee);
EmployeeController employeeController = new EmployeeController(employeeService);
Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@abc.com"));
Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@dce.com"));
Assert.assertNull(employeeService.findEmployeeByEmail("456@abc.com"));
}
}
??該例中,使用startWith替換了eq,可以看到當(dāng)參數(shù)為"123@abc.com"和"123@456.com"時(shí),都返回了employee,而"456@abc.com"則返回了Null??梢姶藭r(shí)參數(shù)是匹配任何以"123"開頭的字符串,這種用法能夠使得參數(shù)的匹配相對(duì)于eq方式更靈活些。
三、任意匹配
??另外一種參數(shù)匹配,即無論入?yún)⑹鞘裁粗担颊J(rèn)為是匹配的。
public class EmployeeControllerTest {
@Test
public void testFindEmployeeByEmail() {
EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
Employee employee = new Employee();
PowerMockito.when(employeeService.findEmployeeByEmail(Mockito.anyString())).thenReturn(employee);
EmployeeController employeeController = new EmployeeController(employeeService);
Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@abc.com"));
Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@dce.com"));
Assert.assertSame(employee, employeeService.findEmployeeByEmail("456@abc.com"));
}
}
??此例中,使用了anyString方式,即無論入?yún)⑹鞘裁醋址挤祷豦mployee。此時(shí)可以看出給定的三個(gè)字符串,都返回了employee。
四、自定義匹配
??除了使用自帶的匹配方式之外,還可以自己定義相應(yīng)的參數(shù)匹配方式。
public class EmployeeControllerTest {
@Test
public void testIsEmployeeEmailAlreadyTaken() {
EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
final String email = "123@abc.com";
PowerMockito.when(employeeService.employeeExists(Mockito.argThat(new ArgumentMatcher<Employee>() {
@Override
public boolean matches(Object employee) {
return ((Employee) employee).getEmail().equals(email);
}
}))).thenReturn(true);
EmployeeController employeeController = new EmployeeController(employeeService);
Assert.assertTrue(employeeController.isEmployeeEmailAlreadyTaken(email));
}
}
??這個(gè)例子看上去稍微有點(diǎn)復(fù)雜。從業(yè)務(wù)代碼可以看出,EmployeeController類的方法isEmployeeEmailAlreadyTaken和EmployeeService類的方法參數(shù)并不一樣,但是又有所關(guān)聯(lián),是使用isEmployeeEmailAlreadyTaken的入?yún)?gòu)造了一個(gè)新的入?yún)ⅰ,F(xiàn)在,我們要想精確匹配入?yún)?,就需要自己?shí)現(xiàn)matcher方法。
??除了上述的一些例子外,Mockito還提供了許多別的參數(shù)匹配的方法,比如any、matches、isNull等等。如何使用這些匹配方式,需要根據(jù)自己的需求來選擇相應(yīng)的模式實(shí)現(xiàn)。另外,上面介紹的參數(shù)匹配同樣適用于Mockito.verify。
??最后,強(qiáng)調(diào)一點(diǎn),對(duì)于多個(gè)參數(shù)的方法,如果我們其中一個(gè)參數(shù)使用了參數(shù)匹配模式,那么所有的參數(shù)都必須使用參數(shù)匹配模式,下面的例子中的使用方式就是錯(cuò)誤的:
PowerMockito.when(mock.findEmployeeByFirstNameAndLastName("Deep", Mockito.anyString())).thenReturn(null);
??正確的方式為:
PowerMockito.when(mock.findEmployeeByFirstNameAndLastName(Mockito.eq("Deep"), Mockito.anyString())).thenReturn(null);