转自:Mockito 中文文档 ( 2.0.26 beta )java
转自:手把手教你 Mockito 的使用git
参数匹配器
Argument Matcher(参数匹配器)github
@Test public void argumentMatchersTest(){ List<String> mock = mock(List.class); when(mock.get(anyInt())).thenReturn("Hello").thenReturn("World"); String result=mock.get(100)+" "+mock.get(200); verify(mock,times(2)).get(anyInt()); assertEquals("Hello World",result); }
@Test public void argumentMatchersTest(){ Map mapMock = mock(Map.class); when(mapMock.put(anyInt(), anyString())).thenReturn("world"); mapMock.put(1, "hello"); verify(mapMock).put(anyInt(), eq("hello")); }
在最后的验证时若是只输入字符串”hello”是会报错的,必须使用Matchers类内建的eq方法。若是将anyInt()换成1进行验证也须要用eq(1)。segmentfault
自定义匹配器-ArgumentMatcher抽象类
自定义参数匹配器的时候须要继承ArgumentMatcher抽象类,它实现了Hamcrest框架的Matcher接口,定义了describeTo方法,因此咱们只须要实现matches方法在其中定义规则便可。
下面自定义的参数匹配器是匹配size大小为2的List:框架
1 class IsListOfTwoElements extends ArgumentMatcher<List> { 2 @ 3 public boolean matches(Object list) { 4 return ((List) list).size() == 2; 5 } 6 } 7 8 @Test 9 public void argumentMatchersTest(){ 10 List mock = mock(List.class); 11 when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true); 12 13 mock.addAll(Arrays.asList("one", "two", "three")); 14 verify(mock).addAll(argThat(new IsListOfTwoElements())); 15 }
argThat(Matcher<T> matcher)方法用来应用自定义的规则,能够传入任何实现Matcher接口的实现类。上例中在stubbing和verify addAll方法时经过argThat(Matcher<T> matcher),传入了自定义的参数匹配器IsListOfTwoElements用来匹配size大小为2的List。由于例子中传入List的元素为三个,因此测试将失败。
较复杂的参数匹配将会下降测试代码的可读性。有时实现参数对象的equals()方法是个不错的选择(Mockito默认使用equals()方法进行参数匹配),它可使测试代码更为整洁。另外,有些场景使用参数捕获器(ArgumentCaptor)要比自定义参数匹配器更加合适。 异步
如何捕获 mock 方法的调用参数
Mockito以java代码风格的形式来验证参数值 : 即经过使用equals()
函数。这也是咱们推荐用于参数匹配的方式,由于这样会使得测试代码更简单、简洁。在某些状况下,当验证交互以后要检测真实的参数值时这将变得有用。例如 :函数
1 @Test 2 public void captureNonGenericArgument() { 3 UserDao userDao = Mockito.mock(UserDao.class); 4 UserService userService = new UserService(userDao); 5 6 userService.saveUser(new User(null, "Yanbin")); 7 8 ArgumentCaptor<User> argumentCaptor = ArgumentCaptor.forClass(User.class); 9 verify(userDao, times(1)).save(argumentCaptor.capture()); 10 11 assertEquals("Yanbin", argumentCaptor.getValue().name); 12 assertEquals("Chicago", argumentCator.getValue().city); //可断言捕获参数的更多特征
从面对被捕获参数 argumentCaptor.getValue()
的断言可看出它比 argThat()
的优点,argThat() 没法告诉咱们不匹配的细节工具
警告 : 咱们建议使用没有测试桩的ArgumentCaptor来验证,由于使用含有测试桩的ArgumentCaptor会下降测试代码的可读性,由于captor是在断言代码块以外建立的。另外一个好处是它能够下降本地化的缺点,由于若是测试桩函数没有被调用,那么参数就不会被捕获。总之,ArgumentCaptor与自定义的参数匹配器相关(能够查看ArgumentMatcher类的文档 )。这两种技术都能用于检测外部传递到Mock对象的参数。然而,使用ArgumentCaptor在如下的状况下更合适 :测试
- 自定义不能被重用的参数匹配器
- 你仅须要断言参数值
咱们一样能够在打桩的时候捕获参数,如ui
1 ArgumentCaptor<User> argumentCaptor = argumentCaptor.forClass(User.class); 2 when(userDao.findUserLike(argumentCaptor.capture)).thenReturn(Mockito.mock(User.class)); 3 4 assertEquals("Yanbin", argumentCaptor.getValue().name);
不能以这种方式在打桩的时候捕获参数:
1 when(userDao.findUserLike(argumentCaptor.capture)).thenReturn(getUser(argumentCaptor.getValue()));
不然会报错:
出错位置在打桩的地方。记住打桩并不等于异步调用,它返回的是个固定值!