1. 概述

在这篇简短的教程中,我们将重点介绍如何使用流行的测试框架 Mockito测试回调函数(Callbacks)

我们会讲解两种解决方案:
✅ 第一种是使用 ArgumentCaptor 抓取回调对象
✅ 第二种是使用更直观的 doAnswer() 方法

如果你对 Mockito 的使用还不太熟悉,可以查看我们整理的 Mockito 系列文章

2. 回调函数简介

回调(Callback)是一种代码片段,作为参数传递给某个方法,并在特定时机被调用执行

回调可以是同步的(立即执行),也可以是异步的(稍后执行)。
最常见的使用场景是 服务调用后处理响应结果

在本教程中,我们使用如下接口作为被测对象的依赖(协作对象):

public interface Service {
    void doAction(String request, Callback<Response> callback);
}

其中,Callback 接口定义如下,用于处理响应:

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 方法会检查响应是否有效,并在有效时设置数据:

private void handleResponse(Response response) {
    if (response.isValid()) {
        response.setData(new Data("Successful data response"));
    }
}

为了清晰起见,这里没有使用 Lambda 表达式,但你也可以这样写得更简洁:

service.doAction("our-request", response -> handleResponse(response));

想了解更多关于 Lambda 的内容?可以看 这篇文章

3. 使用 ArgumentCaptor 捕获回调

下面来看如何使用 Mockito 的 ArgumentCaptor捕获并验证回调对象

@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());
}

📌 步骤解析:

  1. 创建 ActionHandler 并调用其 doAction() 方法(内部会调用服务的回调)
  2. 验证 service.doAction() 是否被调用,并使用 callbackCaptor.capture() 捕获回调对象
  3. 获取捕获的回调对象,手动调用 reply() 方法
  4. 最后断言返回结果是否符合预期

⚠️ 注意:这种方式适合你想手动控制回调的执行时机和参数。

4. 使用 doAnswer() 方法模拟回调

另一种常见的方法是使用 Mockito 的 doAnswer()Answer 对象来 模拟回调行为

@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();
}

📌 步骤解析:

  1. 先创建一个无效的 Response 对象
  2. 使用 doAnswer() 拦截 doAction() 的调用,获取参数中的回调对象
  3. 手动调用 reply(),并验证返回结果是否符合预期
  4. 最后执行 handler.doAction(),触发整个流程

✅ 这种方式适合你希望在模拟方法调用时自动触发回调逻辑的场景。

想了解更多关于如何模拟 void 方法?可以参考 这篇文章

5. 总结

本篇文章我们介绍了两种在 Mockito 中测试回调函数的方式:

  • 使用 ArgumentCaptor 捕获回调对象,手动触发执行
  • 使用 doAnswer() 模拟回调调用过程

两种方式各有适用场景,灵活运用可以让你的单元测试更强大、更可控。

📌 本文所有示例代码均可在 GitHub 项目 中找到。


原始标题:Testing Callbacks with Mockito