1. 概述
在这个简短的教程中,我们将专注于如何使用流行的测试框架Mockito来测试回调函数。
我们将探讨两种解决方案:首先使用ArgumentCaptor
,然后是直观的doAnswer()
方法。
要了解更多关于使用Mockito进行良好测试的信息,请查看我们的Mockito系列教程:这里。
2. 回调函数简介
回调函数是一种作为参数传递给方法的代码,预期在给定时间执行这个参数。这种执行可能是同步的,如立即执行,但更常见的是异步的。
回调函数的一个常见应用场景是在服务交互中处理服务调用的响应。
在本教程中,我们将使用下面所示的Service
接口作为测试用例中的协作方:
public interface Service {
void doAction(String request, Callback<Response> callback);
}
在回调参数中,我们传递一个类,它将使用reply(T response)
方法处理响应:
public interface Callback<T> {
void reply(T response);
}
2.1. 简单的服务
我们将使用一个简单的服务示例来演示如何传递和调用回调:
public void doAction() {
service.doAction("our-request", new Callback<Response>() {
@Override
public void reply(Response response) {
handleResponse(response);
}
});
}
handleResponse
方法会在添加一些数据到Response
对象之前检查响应是否有效:
private void handleResponse(Response response) {
if (response.isValid()) {
response.setData(new Data("Successful data response"));
}
}
为了清晰起见,我们没有使用Java Lambda表达式,但service.doAction
调用也可以更简洁地写成:
service.doAction("our-request", response -> handleResponse(response));
有关Lambda表达式的更多信息,请参阅:这里。
3. 使用ArgumentCaptor
现在让我们看看如何使用Mockito通过ArgumentCaptor
来获取Callback
对象:
@Test
public void givenServiceWithValidResponse_whenCallbackReceived_thenProcessed() {
ActionHandler handler = new ActionHandler(service);
handler.doAction();
verify(service).doAction(anyString(), callbackCaptor.capture());
Callback<Response> callback = callbackCaptor.getValue();
Response response = new Response();
callback.reply(response);
String expectedMessage = "Successful data response";
Data data = response.getData();
assertEquals(
"Should receive a successful message: ",
expectedMessage, data.getMessage());
}
在这个例子中,我们首先创建一个ActionHandler
,然后调用该处理器的doAction
方法。这仅仅是简单地包装了我们简单服务的doAction
方法调用,这就是我们调用回调的地方。
接下来,我们验证doAction
方法确实被调用了,并且第一个参数为anyString()
,第二个参数为callbackCaptor.capture()
,这是捕获Callback
对象的地方。然后可以使用getValue()
方法返回捕获的参数值。
现在我们有了Callback
对象,我们可以创建一个默认有效的Response
对象,然后直接调用reply
方法并断言响应数据具有正确的值。
4. 使用doAnswer()
方法
现在,我们将看看如何使用Mockito的Answer
对象和doAnswer
方法来处理带有回调的虚方法:
@Test
public void givenServiceWithInvalidResponse_whenCallbackReceived_thenNotProcessed() {
Response response = new Response();
response.setIsValid(false);
doAnswer((Answer<Void>) invocation -> {
Callback<Response> callback = invocation.getArgument(1);
callback.reply(response);
Data data = response.getData();
assertNull("No data in invalid response: ", data);
return null;
}).when(service)
.doAction(anyString(), any(Callback.class));
ActionHandler handler = new ActionHandler(service);
handler.doAction();
}
在第二个示例中,我们首先创建一个无效的Response
对象,稍后将在测试中使用。
接下来,我们在mock服务上设置Answer
,当doAction
被调用时,我们拦截调用并使用invocation.getArgument(1)
获取Callback
参数。
最后一步是创建ActionHandler
并调用doAction
,这将触发Answer
的执行。
有关处理虚方法的更多信息,请参阅:这里。
3. 总结
在这篇简短的文章中,我们介绍了使用Mockito测试回调函数的两种不同方法。
如往常一样,示例代码可以在这个GitHub项目中找到。