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

使用Mockito模拟HttpClient.send遇空指针,需按URI返回不同响应

问题解决:Mockito模拟HttpClient根据URI返回不同响应

报错原因分析

你遇到的NullPointerException有两个核心原因:

  1. 匹配器未处理null参数:Mockito在匹配参数时,可能会传入null进行校验,而你的lambda直接调用httpRequest.uri(),没有先判断请求对象是否为null,导致空指针。
  2. Host判断逻辑错误:httpRequest.uri().getHost()返回的是纯主机名(如localhost.com),但你用了带协议的完整地址"http://localhost.com"做匹配,导致永远匹配失败,Mockito无法找到对应存根进而引发后续问题。

正确解决方案

步骤1:创建不同的Mock响应

针对两个接口分别生成Mock的HttpResponse,模拟不同的返回结果:

// 模拟getTokenTwo接口的响应
HttpResponse<String> mockTokenTwoResp = mock(HttpResponse.class);
when(mockTokenTwoResp.statusCode()).thenReturn(200);
when(mockTokenTwoResp.body()).thenReturn("fake-token-two");

// 模拟getTokenOne接口的响应
HttpResponse<String> mockTokenOneResp = mock(HttpResponse.class);
when(mockTokenOneResp.statusCode()).thenReturn(200);
when(mockTokenOneResp.body()).thenReturn("fake-token-one");

步骤2:针对不同URI设置存根

使用argThat匹配器,先判断请求不为null,再根据URI路径或完整地址匹配,分别返回对应的Mock响应:

HttpClient mockHttpClient = mock(HttpClient.class);

// 匹配getTokenTwo方法的请求URI
when(mockHttpClient.send(
    argThat(request -> request != null && 
            request.uri().equals(uriTwo.resolve("/endpointAtUriTwo"))),
    any(HttpResponse.BodyHandler.class)
)).thenReturn(mockTokenTwoResp);

// 匹配getTokenOne方法的请求URI
when(mockHttpClient.send(
    argThat(request -> request != null && 
            request.uri().equals(uriOne.resolve("/endpointAtUriOne"))),
    any(HttpResponse.BodyHandler.class)
)).thenReturn(mockTokenOneResp);

完整测试示例

@Test
void testAuthenticationHandler() throws IOException, InterruptedException {
    // 初始化测试用的基础URI
    URI uriOne = URI.create("http://test-host/one");
    URI uriTwo = URI.create("http://test-host/two");

    // 创建Mock响应
    HttpResponse<String> mockTokenTwoResp = mock(HttpResponse.class);
    when(mockTokenTwoResp.statusCode()).thenReturn(200);
    when(mockTokenTwoResp.body()).thenReturn("fake-token-two");

    HttpResponse<String> mockTokenOneResp = mock(HttpResponse.class);
    when(mockTokenOneResp.statusCode()).thenReturn(200);
    when(mockTokenOneResp.body()).thenReturn("fake-token-one");

    // 创建Mock HttpClient并设置存根
    HttpClient mockHttpClient = mock(HttpClient.class);
    when(mockHttpClient.send(
        argThat(request -> request != null && 
                request.uri().equals(uriTwo.resolve("/endpointAtUriTwo"))),
        any(HttpResponse.BodyHandler.class)
    )).thenReturn(mockTokenTwoResp);

    when(mockHttpClient.send(
        argThat(request -> request != null && 
                request.uri().equals(uriOne.resolve("/endpointAtUriOne"))),
        any(HttpResponse.BodyHandler.class)
    )).thenReturn(mockTokenOneResp);

    // 初始化业务类并触发测试
    AuthenticationHandler handler = new AuthenticationHandler(mockHttpClient, uriOne, uriTwo);
    handler.getTokenOne();

    // 验证HttpClient的send方法被调用两次
    verify(mockHttpClient, times(2)).send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class));
}

额外提示

  • 如果不需要精确匹配完整URI,也可以通过路径片段判断,比如request.uri().getPath().endsWith("/endpointAtUriTwo"),适配更灵活的场景。
  • 确保测试中传入的uriOne和uriTwo与业务代码中使用的基础URI完全一致,否则匹配会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 05:27:46