代码改变世界

使用 Mockito

2015-09-10 12:01  yoogo  阅读(618)  评论(0编辑  收藏  举报

Mockito 的API 相当直观和简单。使用上可以分成四步:

  1. 生成假对象
  2. Stub 假对象
  3. 把 假对象传给依赖它的 SUT(system under test)
  4. Assert 或 Verify 

生成 假 对象:

   假对象分成两种,一种是缺省所有方法都是空实现,返回值为null; 还有一种其所有方法缺省都是被mock的类的实现。我们分别把它们称为mock 对象和 spy 对象。 

  可以基于类或接口生成 mock 对象,而创建 spy 对象只能基于实例或类。两者都可以通过Mockito的静态方法或标注创建: mock(BASE), spy(BASE); 或 @Mock BASE mockObj , @Spy  BASE  spyObj . 

Sbub 假对象:

  mock 和 spy 对象的方法虽然都有缺省的实现,但我们往往期望它能按我们的期望和待测对象交互。stub 就是做这个的。 Sbub 的方式有两种:

  1. when(mockObj.foo(argsMatcher)).thenXx(Xx);
  2. doXx(Xx).when(spyOrMockObj).foo(argsMatcher);

显然,方式1不适合 void 方法。此外,如果是 spy 对象,方法的缺省实现会在 sbub 时执行,所以它也不适用 spy 对象。同样的道理它不适合已经 sbub 过的方法上。

  doXx , thenXx  可以直接指定返回值 - doReturn(ojb)/thenReturn(obj) 或抛出异常 - doThrow(eOjbOrClass)/thenThrow(eObjOrClass)。 也可以doCallRealMethod()/thenCallRealMethod(), 显然这时假对象不能是基于接口的。 如果有复杂的逻辑决定不同的结果(如,有时return a,有时 return b,有时 throw E ),则可以 doAnswer(answer)/thenAnswer(anwer),这里的 answer 显然需要自己实现。

  sbut 定制了 SUT 与假对象指定的方法交互时应得到的结果。显然,“指定的方法”是通过方法名和参数确定的。方法名在 mockito 中是等值匹配的。但对于参数,匹配方式就不仅限于此了。如果直接给值,则匹配条件是 argSpecified.equals(argReal)。匹配参数还可以通过Mockito 静态方法提供的大量匹配器来表达。可大致分成5种:string,null, same, equal 和 that。 that 就是允许通过实现 ArgumentMatcher 来实现,不表。这里注意多个参数是,使用匹配器不能同时使用值,应该用 eq(值)转换下。

 

把 假对象传给依赖它的 SUT

  这里没什么好说的。但注意,SUT 可能与从假对象得到的第三方对象交互,那可能需要在stub 时包含第三方对象,甚至是对象链。 

Assert 或 Verify 

  也就是验证 SUT 与假对象的交互。 包含这三个方面:次数,顺序,和参数。基本格式为 verify(mockOrSpy, TIME).foo(argsMatcher)。 

  表达次数的函数好记,不过是范围,极限值。 注意,还有一个方法 timeOut(mills), 意味着在等待指定的时间后再做verify。 

  顺序验证能则需先包装假对象为InOder, 用它验证假对象则就是顺序敏感的:

    InOrder inOrder = inOrder(mockOrSpy...) ;

    inOrder.verify(mockOrSpy).foo(argMatcher) ; 

  最后是参数验证,sbub 阶段使用的参数匹配方式可行。除此之外,还有种更合verify语义的方式。可以先捕获参数,然后 Assert :

1   ArgumentCaptor<Foo>  captor = ArgumentCaptor.forClass(Foo.class);
2   verify(mockOrSpy).bar(captor.capture());
3   Foo usedArg = captor.getValue();
4   assertEquals(expected, usedArg);

好啰嗦:(