Mockito是一个方便的java测试Mock工具。
当我们做TDD或者单元测试的时候,为了消除当前被测对象和其依赖之间的关系,经常使用Mockito。
本篇文章只涉及如何使用Mockito的Partial Mock。关于Mockito的其他用法,请参照Mockito
###1. 什么是Partial Mock
在单元测试的过程中,偶尔会出现这种情况。对于一个对象,某些方法需要被mock,而某些方法希望被直接调用,这时候,我们就需要借助Partial Mock。
###2. 使用Partial Mock的场景
在如下两种场景中,Partial Mock就显得相当犀利:
a) 测试存在具体方法的抽象类
public abstract class AbstractHandler {
public String greet() {
return "Hello " + fetchName() + "!";
}
protected abstract String fetchName();
}
如上代码所示,抽象类AbstractHandler中定义了方法greet(),并且该方法存在一定逻辑。
此时,如果希望测试greet(),可以选择两种方式:
- 构建其派生非抽象类,如ConcertHandler,再进行测试。
- 使用Partial Mock,它可以省去构建派生类的步骤,直接对该抽象类进行测试,代码如下所示:
public class AbstractHandlerTest {
@Test
public void shouldCallRealMethodsAndFakeAbstractMethod() {
AbstractHandler handler = mock(AbstractHandler.class);
when(handler.greet()).thenCallRealMethod();
when(handler.fetchName()).thenReturn("Geek");
assertThat(handler.greet(), is("Hello Geek!"));
}
}
如代码所示,对于抽象方法fechName(),直接mock其返回值
when(handler.fetchName()).thenReturn(“Geek”);
对于被测方法greet(),则使用thenCallRealMethod()使Mock对象调用真实的实现方法。
when(handler.greet()).thenCallRealMethod();
b)测试过分依赖于I/O操作的类
public class BooksController {
protected Map<String, Date> fetchBooks(){
//fetch the books from different publishing company.
service1.retrieveBooks();
service2.retrieveBooks();
......
service10.retrieveBooks();
}
protected List<String> getPublishedBooks(){
books = fetchBooks();
//only pick up the books published.
}
}
如上代码所示,类BooksController中定义了方法fetchBooks(),并且该方法严重依赖于I/O操作。因为fetchBooks()从不同的供应商那里获取最近的书籍信息。