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

Mock RestTemplate exchange方法返回null问题求助

问题:Mock RestTemplate#exchange始终返回null

我参考了多篇相关技术帖子,尝试多种方式Mock RestTemplate#exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) 方法(未传入uriVariables),但始终无法获取非空返回值。

业务源码(简化后)

Request request = new Request();
request.setDataId(1);
String query = "query ($ request:Request!)" + 
            "{" + 
            "    fetchData(request:$request)" + 
            "    {" + 
            "        planId" + 
            "    }" +
            " }";

RequestBody requestBody = new RequestBody(query, Collections.singletonMap("request", request));   
HttpEntity<RequestBody> requestEntity = new HttpEntity<>(requestBody, createHttpHeaders());   
return restTemplate.exchange("http://localhost:8080/gql", HttpMethod.POST, requestEntity, JsonNode.class);

private HttpHeaders createHttpHeaders() {
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
    return headers;
}

RequestBody类(使用Lombok)

@Getter
@AllArgsConstructor
public class RequestBody implements Serializable {
  private static final long serialVersionUID = -203524485553511477L;
  private String query;
  private Map<String,Object> variables;
}

测试代码

@Mock
private RestTemplate restTemplate;

@Mock
private ObjectMapper objectMapper;

@InjectMocks
private FetchDataService fetchDataService;
  
@Test
public void testFetchData() throws IOException {
    String json = new String(Files.readAllBytes(Paths.get("src/test/resources/Data.json")));
    ObjectMapper testMapper = new ObjectMapper();
    JsonNode expectedResponse = testMapper.readTree(json);
    
    when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(HttpEntity.class), any(Class.class)))
        .thenReturn(new ResponseEntity<>(expectedResponse, HttpStatus.OK));  
    
    ResponseEntity<JsonNode> response = fetchDataService.getData();   
}

上述代码中expectedResponse是JsonNode实例,但response的body始终为null。我已通过以下代码验证调用确实发生:

Mockito.verify(restTemplate)
    .exchange(anyString(), any(HttpMethod.class), any(HttpEntity.class), any(Class.class));

环境:JUnit 5、Spring Boot 2.6.7、JDK 11


解决方案

1. 匹配正确的exchange重载方法

你Mock的是4参数的exchange方法,但实际调用的是5参数(最后一个为可变参数Object... uriVariables)的重载版本。不传可变参数时,Java会默认传递空数组,因此需要Mock对应重载方法:

when(restTemplate.exchange(
    anyString(), 
    any(HttpMethod.class), 
    any(HttpEntity.class), 
    any(Class.class),
    any(Object[].class) // 匹配可变参数
)).thenReturn(new ResponseEntity<>(expectedResponse, HttpStatus.OK));

或简化为:

when(restTemplate.exchange(
    anyString(), 
    any(HttpMethod.class), 
    any(HttpEntity.class), 
    any(Class.class),
    any()
)).thenReturn(new ResponseEntity<>(expectedResponse, HttpStatus.OK));

2. 确保Mock初始化正确

测试类需添加@ExtendWith(MockitoExtension.class)(JUnit 5),否则@Mock和@InjectMocks无法完成初始化:

@ExtendWith(MockitoExtension.class)
public class FetchDataServiceTest {
    // ... 测试代码
}

3. 验证expectedResponse有效性

确认Data.json路径正确、内容为合法JSON,可在测试中添加断言:

assertNotNull(expectedResponse, "预期响应JSON不能为空");

4. 修复业务源码变量冲突

业务代码中Request request与HttpEntity<RequestBody> request重名,建议重命名为requestEntity避免潜在逻辑问题:

HttpEntity<RequestBody> requestEntity = new HttpEntity<>(requestBody, createHttpHeaders());   
return restTemplate.exchange("http://localhost:8080/gql", HttpMethod.POST, requestEntity, JsonNode.class);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:15:42