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

Okhttp3如何在Client中定义特定Request避免单元测试空指针异常

问题原因

你遇到的NullPointerException是Mockito桩配置未命中导致的:

  • OkHttp的Request类未重写equals()方法,默认基于对象引用匹配
  • 你在测试代码中手动构造的Request实例,和递归方法内部生成的Request虽然属性完全一致,但属于两个不同的对象
  • 当你用具体Request实例配置mockClient.newCall()的桩时,参数匹配失败,方法返回null,后续调用null.execute()就触发了空指针

解决方案

方案1:自定义参数匹配规则(推荐,适合多轮迭代场景)

用Mockito的argThat匹配器,按请求的实际属性匹配,不需要依赖对象引用,可精准匹配不同分页的请求:

// 匹配第一页请求
ArgumentMatcher<Request> page1Matcher = request -> 
    "https://localhost:8080/getData".equals(request.url().toString())
    && "application/json".equals(request.header("Content-Type"))
    && authCodeSuccess.equals(request.header("Authorization"));

// 匹配第二页请求(替换为你实际的下页地址规则)
ArgumentMatcher<Request> page2Matcher = request -> 
    "https://localhost:8080/getData?page=2".equals(request.url().toString())
    && "application/json".equals(request.header("Content-Type"))
    && authCodeSuccess.equals(request.header("Authorization"));

// 分别给不同请求打桩返回对应响应
Call page1Call = mock(Call.class);
when(page1Call.execute()).thenReturn(/* 构造带newPage字段的第一页响应 */);
when(mockClient.newCall(argThat(page1Matcher))).thenReturn(page1Call);

Call page2Call = mock(Call.class);
when(page2Call.execute()).thenReturn(/* 构造不带newPage字段的最后一页响应 */);
when(mockClient.newCall(argThat(page2Matcher))).thenReturn(page2Call);

方案2:按调用顺序返回响应(适合简单场景)

如果不需要严格校验请求参数,仅模拟顺序调用的返回结果,可以保留any()匹配,给execute()方法配置连续返回值:

when(mockClient.newCall(any())).thenReturn(remoteCall);
// 第一次调用execute返回带newPage的第一页响应,第二次返回不带newPage的最后一页响应
when(remoteCall.execute()).thenReturn(page1Response, page2Response);

额外优化建议

生产环境中建议用try-with-resources包裹Response实例,避免Http连接泄漏:

try (okhttp3.Response response = client.newCall(request).execute()) {
    // 处理响应逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 09:39:03