我正在使用Mockito进行服务层单元测试。我不清楚何时使用doAnswer
和thenReturn
。
有人可以详细帮助我吗?到目前为止,我已经尝试了使用thenReturn
。
thenReturn
或doReturn
。当您调用模拟方法时,将返回定义的值。
thenReturn(T value)
设置在调用方法时返回的值。
@Test
public void test_return() throws Exception {
Dummy dummy = mock(Dummy.class);
int returnValue = 5;
// choose your preferred way
when(dummy.stringLength("dummy")).thenReturn(returnValue);
doReturn(returnValue).when(dummy).stringLength("dummy");
}
Answer
用于在调用模拟方法时需要执行其他操作的情况,例如在您需要根据此方法调用的参数计算返回值时。
当您想要使用通用
Answer
存根void方法时,请使用doAnswer()
。Answer指定了在与模拟对象交互时执行的操作和返回的返回值。
@Test
public void test_answer() throws Exception {
Dummy dummy = mock(Dummy.class);
Answer<Integer> answer = new Answer<Integer>() {
public Integer answer(InvocationOnMock invocation) throws Throwable {
String string = invocation.getArgumentAt(0, String.class);
return string.length() * 2;
}
};
// choose your preferred way
when(dummy.stringLength("dummy")).thenAnswer(answer);
doAnswer(answer).when(dummy).stringLength("dummy");
}
doAnswer
和 thenReturn
在以下情况下才会执行相同的操作:
让我们模拟这个 BookService。
public interface BookService {
String getAuthor();
void queryBookTitle(BookServiceCallback callback);
}
您可以使用doAnswer
和thenReturn
来桩造getAuthor()
。
BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return "Joshua";
}
}).when(service).getAuthor();
请注意,在使用doAnswer
时,您无法将when
方法传递给它。// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());
那么,什么情况下您会使用doAnswer
而不是thenReturn
呢? 我可以想到两种用例:
使用doAnswer
,您可以在方法调用时执行一些额外的操作。例如,在查询书名时触发回调。
BookServiceCallback callback = new BookServiceCallback() {
@Override
public void onSuccess(String bookTitle) {
assertEquals("Effective Java", bookTitle);
}
};
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
callback.onSuccess("Effective Java");
// return null because queryBookTitle is void
return null;
}
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
在Spy Mockito中使用when-thenReturn将调用真实方法,然后存根您的答案。如果您不想调用真实方法,就像在此示例中一样,这可能会导致问题:
List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));
使用 doAnswer 我们可以安全地进行存根。
List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));
实际上,如果您不想在方法调用时执行其他操作,您可以直接使用doReturn
。
List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));
doAnswer(new Answer() { ... return null;}
时,我在Eclipse中会收到一个警告:“Answer is a raw type. References to generic type Answer<T> should be parameterized”。除了忽略警告之外,有没有解决这个问题的方法? - LazR最简单的答案是:
code = UUID.randomUUID()
,我发现使用mockito
实现这一点是不可能的。 - zhuguoweireturn UUID.randomUUID();
实现Answer
。 - Roland WeislederAnswer
是一个函数式接口,所以使用Java 8,你可以用一个lambda表达式来替换它。如果代码不够清晰,也可以进行其他常见和不常见的重构。 - Roland Weisleder