如何为Quarkus的ResponseExceptionMapper与ExceptionMapper编写测试获取代码覆盖率
两类异常映射器的单元测试实现示例
以下示例基于Junit 5编写,无需启动Web容器即可完成逻辑覆盖,可直接适配你项目中的现有Mapper实现。
1. ExceptionMapper 测试示例
首先是常见的自定义业务异常对应的ExceptionMapper实现参考:
// 自定义业务异常类 public class BizException extends RuntimeException { private final int code; public BizException(int code, String message) { super(message); this.code = code; } public int getCode() { return code; } } // ExceptionMapper实现类 @Provider public class BizExceptionMapper implements ExceptionMapper<BizException> { @Override public Response toResponse(BizException e) { return Response.status(e.getCode()) .entity(Map.of("code", e.getCode(), "message", e.getMessage())) .type(MediaType.APPLICATION_JSON) .build(); } }
对应的单元测试代码:
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; public class BizExceptionMapperTest { // 直接实例化Mapper类,无需容器启动 private final BizExceptionMapper exceptionMapper = new BizExceptionMapper(); @Test public void testToResponseNormal() { // 构造测试入参 int expectedCode = 400; String expectedMsg = "请求参数非法"; BizException testException = new BizException(expectedCode, expectedMsg); // 执行映射逻辑 Response result = exceptionMapper.toResponse(testException); // 校验返回结果是否符合预期 assertEquals(expectedCode, result.getStatus()); assertEquals(MediaType.APPLICATION_JSON_TYPE, result.getMediaType()); Map<String, Object> entity = (Map<String, Object>) result.getEntity(); assertEquals(expectedCode, entity.get("code")); assertEquals(expectedMsg, entity.get("message")); } }
2. ResponseExceptionMapper 测试示例
首先是ResponseExceptionMapper的实现参考,示例为处理5xx状态码的映射器:
@Provider public class ServerErrorResponseMapper implements ResponseExceptionMapper<RuntimeException> { @Override public boolean handles(int status, MultivaluedMap<String, Object> headers) { // 仅处理500-599区间的服务端错误状态码 return status >= 500 && status < 600; } @Override public RuntimeException toThrowable(Response response) { String errorInfo = response.readEntity(String.class); return new RuntimeException("服务端调用异常: " + errorInfo); } @Override public int getPriority() { return 10; } }
对应的单元测试代码:
import org.junit.jupiter.api.Test; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.Response; import static org.junit.jupiter.api.Assertions.*; public class ServerErrorResponseMapperTest { private final ServerErrorResponseMapper responseMapper = new ServerErrorResponseMapper(); @Test public void testHandlesStatus() { MultivaluedHashMap<String, Object> testHeaders = new MultivaluedHashMap<>(); // 校验5xx状态码可被处理 assertTrue(responseMapper.handles(500, testHeaders)); assertTrue(responseMapper.handles(503, testHeaders)); assertTrue(responseMapper.handles(599, testHeaders)); // 校验非5xx状态码不会被处理 assertFalse(responseMapper.handles(200, testHeaders)); assertFalse(responseMapper.handles(404, testHeaders)); assertFalse(responseMapper.handles(600, testHeaders)); } @Test public void testToThrowable() { String expectedError = "数据库连接超时"; Response testResponse = Response.status(500).entity(expectedError).build(); RuntimeException resultException = responseMapper.toThrowable(testResponse); assertEquals("服务端调用异常: " + expectedError, resultException.getMessage()); } @Test public void testGetPriority() { assertEquals(10, responseMapper.getPriority()); } }
补充说明:如果你的Mapper类中存在依赖注入的组件(比如日志类、配置类),可以用Mockito模拟对应依赖后注入到Mapper实例中,再执行测试即可。如果Mapper中存在多分支逻辑,针对每个分支单独构造测试用例就能覆盖所有代码路径。
内容的提问来源于stack exchange,提问作者Sandra
相关产品推荐
相关产品推荐

