在mock方法时,对于方法的参数匹配是有要求的,只有要执行的方法的参数匹配mock方法里面的参数时,该mock方法才会起作用。Powermock提供了很多种参数匹配的方式,比如,如果需要精确地匹配参数,可以使用equal方式;如果需要灵活地匹配参数,可以使用any方式。下面,我们就来简单地介绍下mock方法时的参数匹配。
一、精确匹配
还是先来看下被测试代码:
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类中定义了两个方法,一个是findEmployeeByEmail,根据email查询员工,调用employeeService.findEmployeeByEmail方法;另一个方法是isEmployeeEmailAlreadyTaken方法,判断某个员工是否存在,调用employeeService.employeeExists方法。
现在看下测试代码:
public class EmployeeControllerTest {
@Test
public void testFindEmployeeByEmail() {
EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
Employee employee = new Employee();
PowerMockito.when(employeeService.findEmployeeByEmail(Mockito.eq("[email protected]"))).thenReturn(employee);
EmployeeController employeeController = new EmployeeController(employeeService);
Assert.assertSame(employee, employeeController.findEmployeeByEmail("[email protected]"));
Assert.assertNull(employeeController.findEmployeeByEmail("[email protected]"));
}
}
从上述测试方法可以看到,在模拟employeeService.findEmployeeByEmail方法时使用了eq方法,这个就是精确匹配模式,执行参数完全匹配该参数时,才会返回employee。
二、模糊匹配
有时候,我们想要在匹配参数时更灵活些,可以使用模糊匹配。看下下面的测试方法:
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("[email protected]"));
Assert.assertSame(employee, employeeController.findEmployeeByEmail("[email protected]"));
Assert.assertNull(employeeService.findEmployeeByEmail("[email protected]"));
}
}
该例中,使用startWith替换了eq,可以看到当参数为"[email protected]"和"[email protected]"时,都返回了employee,而"[email protected]"则返回了Null。可见此时参数是匹配任何以"123"开头的字符串,这种用法能够使得参数的匹配相对于eq方式更灵活些。
三、任意匹配
另外一种参数匹配,即无论入参是什么值,都认为是匹配的。
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("[email protected]"));
Assert.assertSame(employee, employeeController.findEmployeeByEmail("[email protected]"));
Assert.assertSame(employee, employeeService.findEmployeeByEmail("[email protected]"));
}
}
此例中,使用了anyString方式,即无论入参是什么字符串,都返回employee。此时可以看出给定的三个字符串,都返回了employee。
四、自定义匹配
除了使用自带的匹配方式之外,还可以自己定义相应的参数匹配方式。
public class EmployeeControllerTest {
@Test
public void testIsEmployeeEmailAlreadyTaken() {
EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
final String email = "[email protected]";
PowerMockito.when(employeeService.employeeExists(Mockito.argThat(new ArgumentMatcher() {
@Override
public boolean matches(Object employee) {
return ((Employee) employee).getEmail().equals(email);
}
}))).thenReturn(true);
EmployeeController employeeController = new EmployeeController(employeeService);
Assert.assertTrue(employeeController.isEmployeeEmailAlreadyTaken(email));
}
}
这个例子看上去稍微有点复杂。从业务代码可以看出,EmployeeController类的方法isEmployeeEmailAlreadyTaken和EmployeeService类的方法参数并不一样,但是又有所关联,是使用isEmployeeEmailAlreadyTaken的入参构造了一个新的入参。现在,我们要想精确匹配入参,就需要自己实现matcher方法。
除了上述的一些例子外,Mockito还提供了许多别的参数匹配的方法,比如any、matches、isNull等等。如何使用这些匹配方式,需要根据自己的需求来选择相应的模式实现。另外,上面介绍的参数匹配同样适用于Mockito.verify。
最后,强调一点,对于多个参数的方法,如果我们其中一个参数使用了参数匹配模式,那么所有的参数都必须使用参数匹配模式,下面的例子中的使用方式就是错误的:
PowerMockito.when(mock.findEmployeeByFirstNameAndLastName("Deep", Mockito.anyString())).thenReturn(null);
正确的方式为:
PowerMockito.when(mock.findEmployeeByFirstNameAndLastName(Mockito.eq("Deep"), Mockito.anyString())).thenReturn(null);