Mock方法时的参数匹配

  在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);

你可能感兴趣的:(Mock方法时的参数匹配)