异常未转换问题:IOException未被包装为RuntimeException
问题描述
我编写了发起HTTP请求的方法:
public String executeRequest(HttpRequest request) { try { return httpResourceProvider.getHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()) .body(); } catch (IOException | InterruptedException e) { log.atSevere().withCause(e).log("Could not do stuff"); throw new RuntimeException(e); } }
单元测试中,我模拟send方法抛出IOException,验证是否会转换为RuntimeException抛出,测试代码如下:
@Mock private HttpClient httpClient; // 初始化Mock等操作 @Test public void testRequestThrowsIOException() throws IOException, InterruptedException { when(httpClient.send(eq(httpRequest), eq(HttpResponse.BodyHandlers.ofString()))).thenThrow(new IOException()); assertThrows(RuntimeException.class, () -> myRepository.getSchema(TEST_SCHEMA_ID)); }
但测试因抛出IOException失败,未完成异常转换,错误日志:
SEVERE: Could not call Github to fetch schema java.io.IOException at *.executeRequest(*.java:33)
备注:HttpResourceProvider已被Mock,返回Mock的HttpRequest实例。
问题原因
参数匹配失败,Mock逻辑未生效:
测试中使用eq()对send方法的两个参数做严格匹配,但存在两处匹配失败的可能:- 请求对象不匹配:测试里的
eq(httpRequest)对应的实例,和实际调用executeRequest时传入的HttpRequest不是同一个对象,导致Mock的抛异常逻辑没触发。 - BodyHandler实例不匹配:
HttpResponse.BodyHandlers.ofString()每次调用都会生成新的实例,eq()会因为实例不同匹配失败,Mock逻辑无法生效。
当Mock逻辑未触发时,如果HttpClient是未正确配置的实例,调用真实send方法会抛出原生IOException,且未触发代码里的异常转换逻辑。
- 请求对象不匹配:测试里的
Mock对象未正确关联:
虽然Mock了HttpResourceProvider,但没确保它的getHttpClient()返回测试中定义的@Mock HttpClient实例。如果返回的是真实HttpClient或其他未配置Mock的实例,调用send会抛出真实IOException,无法触发异常转换。代码版本不一致:
错误日志里的日志内容是Could not call Github to fetch schema,但你贴出的代码里日志是Could not do stuff,说明测试运行的代码和当前贴出的代码不一致,异常转换逻辑可能未包含在实际运行的代码中。
解决建议
- 调整参数匹配方式,改用宽松匹配替代严格的
eq():when(httpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenThrow(new IOException()); - 确保
HttpResourceProvider的getHttpClient()返回测试中的Mock实例:when(httpResourceProvider.getHttpClient()).thenReturn(httpClient); - 核对测试运行的代码与当前贴出的代码一致,确认异常捕获和转换逻辑正确。
内容的提问来源于stack exchange,提问作者ritratt
相关产品推荐
相关产品推荐

