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

