You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写JUnit测试覆盖FutureCallback<HttpResponse>三类回调场景

解决方案

核心思路

CloseableHttpAsyncClient是Spring注入的依赖,我们可以通过Mockito捕获调用execute方法时传入的FutureCallback实例,主动触发三个回调方法,即可覆盖对应的代码分支。

具体实现步骤

1. 引入基础测试依赖

如果项目还没有引入相关测试依赖,可补充如下配置(以Maven为例):

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

2. 编写单元测试类

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.env.Environment;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Method;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class SplunkLoggerTest {

    @Mock
    private Environment environment;
    @Mock
    private CloseableHttpAsyncClient httpClient;
    @InjectMocks
    private SplunkLogger splunkLogger;

    // 用于捕获execute方法传入的FutureCallback实例
    private final ArgumentCaptor<FutureCallback<HttpResponse>> callbackCaptor = ArgumentCaptor.forClass(FutureCallback.class);

    // 通用前置配置:设置非local环境,才会走到HTTP请求逻辑
    private void initNonLocalEnv() {
        when(environment.getActiveProfiles()).thenReturn(new String[]{"dev"});
    }

    // 反射调用private的log方法,也可以将log调整为包私有省略反射逻辑
    private void invokeLogMethod(SplunkMessage message) throws Exception {
        Method logMethod = SplunkLogger.class.getDeclaredMethod("log", SplunkMessage.class);
        logMethod.setAccessible(true);
        logMethod.invoke(splunkLogger, message);
    }

    @Test
    public void testCompletedCallback() throws Exception {
        initNonLocalEnv();
        SplunkMessage testMessage = new SplunkMessage();
        // 构造模拟返回的响应对象
        HttpResponse mockResponse = mock(HttpResponse.class);
        HttpEntity mockEntity = mock(HttpEntity.class);
        when(mockResponse.getEntity()).thenReturn(mockEntity);
        when(mockEntity.getContent()).thenReturn(new ByteArrayInputStream("splunk返回成功".getBytes()));

        invokeLogMethod(testMessage);

        // 捕获回调实例并主动触发completed方法
        verify(httpClient).execute(any(HttpPost.class), callbackCaptor.capture());
        callbackCaptor.getValue().completed(mockResponse);
    }

    @Test
    public void testFailedCallback() throws Exception {
        initNonLocalEnv();
        SplunkMessage testMessage = new SplunkMessage();

        invokeLogMethod(testMessage);

        // 捕获回调实例并主动触发failed方法
        verify(httpClient).execute(any(HttpPost.class), callbackCaptor.capture());
        callbackCaptor.getValue().failed(new RuntimeException("请求异常模拟"));
    }

    @Test
    public void testCancelledCallback() throws Exception {
        initNonLocalEnv();
        SplunkMessage testMessage = new SplunkMessage();

        invokeLogMethod(testMessage);

        // 捕获回调实例并主动触发cancelled方法
        verify(httpClient).execute(any(HttpPost.class), callbackCaptor.capture());
        callbackCaptor.getValue().cancelled();
    }
}

注意事项

  • 若不想用反射调用private方法,可将log方法的访问修饰符调整为包私有,同包下的测试类可直接调用无需反射。
  • 上述测试执行后,FutureCallback的三个方法逻辑都会被触发,覆盖率统计工具会对应标记这三个分支为已覆盖。

内容的提问来源于stack exchange,提问作者kumar001

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 20:09:03