美文网首页Java单元测试
Mock方法时的参数匹配

Mock方法时的参数匹配

作者: SeanPenn | 来源:发表于2018-06-28 00:22 被阅读0次

      在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("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方法时使用了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("123@abc.com"));
            Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@dce.com"));
            Assert.assertNull(employeeService.findEmployeeByEmail("456@abc.com"));
        }
    }
    

      该例中,使用startWith替换了eq,可以看到当参数为"123@abc.com"和"123@456.com"时,都返回了employee,而"456@abc.com"则返回了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("123@abc.com"));
            Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@dce.com"));
            Assert.assertSame(employee, employeeService.findEmployeeByEmail("456@abc.com"));
        }
    }
    

      此例中,使用了anyString方式,即无论入参是什么字符串,都返回employee。此时可以看出给定的三个字符串,都返回了employee。

    四、自定义匹配

      除了使用自带的匹配方式之外,还可以自己定义相应的参数匹配方式。

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

      这个例子看上去稍微有点复杂。从业务代码可以看出,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方法时的参数匹配

        本文链接:https://www.haomeiwen.com/subject/aifwyftx.html