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

如何用Mockito模拟CompletableFuture?模拟后未获预期结果

解决方法

1. 核心思路:别直接模拟CompletableFuture,要模拟RestTemplate

你的代码里CompletableFuture只是异步执行了restTemplate.exchange,所以问题根源不在CompletableFuture本身,只要把RestTemplate的exchange方法模拟好,异步流程自然能返回预期结果。

2. 具体步骤

第一步:确保RestTemplate是可注入的依赖

先保证你的RestTemplate是通过@Autowired这类方式注入的,不是在方法里直接new的,不然Mockito没法替换它。

第二步:构造模拟响应并替换RestTemplate行为

// 1. 构造你想要的JsonNode响应体
ObjectMapper objectMapper = new ObjectMapper();
JsonNode expectedBody = objectMapper.createObjectNode().put("status", "success").put("data", "test_content");

// 2. 把响应包装成ResponseEntity
ResponseEntity<JsonNode> mockResponse = new ResponseEntity<>(expectedBody, HttpStatus.OK);

// 3. 用Mockito让RestTemplate的exchange方法返回上面的模拟响应
when(restTemplate.exchange(
    eq(baseUrl),  // 匹配你的baseUrl
    eq(HttpMethod.GET),  // 匹配请求方法
    any(HttpEntity.class),  // 匹配任意HttpEntity(如果需要精确匹配headers,换成eq(request))
    eq(JsonNode.class)  // 匹配返回类型
)).thenReturn(mockResponse);

第三步:测试时的注意事项

  • 调用requestCompletableFuture.get()时,要处理InterruptedException和ExecutionException,可以直接在测试方法上声明抛出这两个异常,或者用try-catch捕获后排查问题。
  • 如果测试时遇到线程阻塞问题,不用慌,因为模拟的RestTemplate方法是同步返回的,CompletableFuture会很快完成。

完整测试示例

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.concurrent.CompletableFuture;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class YourServiceTest {

    @Mock
    private RestTemplate restTemplate;

    @InjectMocks
    private YourService yourService; // 假设你的业务代码在这个类里

    private final String baseUrl = "https://your-api-url.com";

    @Test
    void testAsyncRestCall() throws Exception {
        // 构造预期响应
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode expectedBody = objectMapper.createObjectNode().put("data", "mock-data");
        ResponseEntity<JsonNode> mockResponse = new ResponseEntity<>(expectedBody, HttpStatus.OK);

        // 模拟RestTemplate行为
        when(restTemplate.exchange(eq(baseUrl), eq(HttpMethod.GET), any(HttpEntity.class), eq(JsonNode.class)))
                .thenReturn(mockResponse);

        // 调用业务方法
        JsonNode actualResponse = yourService.executeAsyncRequest();

        // 校验结果
        assertEquals("mock-data", actualResponse.get("data").asText());
    }
}

常见排查点

  • 如果还是不对,先检查参数匹配是否准确:比如baseUrl是否和测试里的一致,headers是否需要精确匹配(如果是的话,把any(HttpEntity.class)换成eq(request))。
  • 可以捕获ExecutionException查看具体错误:
try {
    JsonNode response = requestCompletableFuture.get();
} catch (ExecutionException e) {
    e.getCause().printStackTrace(); // 这里能看到具体失败原因
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 05:40:31