如何用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
相关产品推荐
相关产品推荐

