Files
baiyue-firstleg/common-web/src/test/java/com/baiyue/common/web/GlobalExceptionHandlerTest.java
T
2026-08-21 11:43:03 +08:00

122 lines
5.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.baiyue.common.web;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.servlet.resource.NoResourceFoundException;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import java.lang.reflect.Method;
import static org.assertj.core.api.Assertions.assertThat;
@DisplayName("全局异常响应")
class GlobalExceptionHandlerTest {
private final GlobalExceptionHandler handler = new GlobalExceptionHandler();
@Test
void businessExceptionKeepsBusinessCodeAndCorrelation() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAttribute(CorrelationContext.REQUEST_ID, "r1");
request.setAttribute(CorrelationContext.TRACE_ID, "t1");
var response = handler.handleBusiness(new BizException("inventory is locked"), request);
assertThat(response.getStatusCode().value()).isEqualTo(200);
assertThat(response.getBody().code()).isEqualTo(ResultCode.BUSINESS_ERROR.code());
assertThat(response.getBody().requestId()).isEqualTo("r1");
}
@Test
void invalidQueryParameterTypeMapsToBadRequest() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
Method method = GlobalExceptionHandlerTest.class.getDeclaredMethod("paging", long.class);
MethodParameter parameter = new MethodParameter(method, 0);
MethodArgumentTypeMismatchException exception = new MethodArgumentTypeMismatchException(
"abc", Long.class, "page", parameter, new NumberFormatException("abc"));
var response = handler.handleBadRequest(exception, request);
assertThat(response.getStatusCode().value()).isEqualTo(200);
assertThat(response.getBody().code()).isEqualTo(ResultCode.BAD_REQUEST.code());
}
@Test
void missingRequiredRequestHeaderMapsToBadRequest() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
Method method = GlobalExceptionHandlerTest.class.getDeclaredMethod("paging", long.class);
MethodParameter parameter = new MethodParameter(method, 0);
var response = handler.handleBadRequest(
new MissingRequestHeaderException("Idempotency-Key", parameter), request);
assertThat(response.getStatusCode().value()).isEqualTo(200);
assertThat(response.getBody().code()).isEqualTo(ResultCode.BAD_REQUEST.code());
}
@Test
void validationDetailsAreIncludedInMessageAndData() {
MockHttpServletRequest request = new MockHttpServletRequest();
BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(new Object(), "request");
bindingResult.addError(new FieldError("request", "carrierId", "不能为null"));
bindingResult.addError(new FieldError("request", "carrierName", "不能为空"));
var response = handler.handleBinding(new BindException(bindingResult), request);
assertThat(response.getBody().code()).isEqualTo(ResultCode.VALIDATION_FAILED.code());
assertThat(response.getBody().message()).isEqualTo("carrierId: 不能为null;carrierName: 不能为空");
assertThat(response.getBody().data()).containsEntry("carrierId", "不能为null")
.containsEntry("carrierName", "不能为空");
}
@Test
void recordsBusinessFailureMetricByFiniteResultCode() {
SimpleMeterRegistry registry = new SimpleMeterRegistry();
ReflectionTestUtils.setField(handler, "meterRegistry", registry);
handler.handleBusiness(new BizException(ResultCode.CONFLICT, "duplicate"),
new MockHttpServletRequest());
assertThat(registry.get("baiyue.api.business.failures")
.tag("code", ResultCode.CONFLICT.code()).counter().count()).isEqualTo(1.0);
}
@Test
void responseStatusConflictMapsToCanonicalConflictInsteadOfInternalError() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAttribute(CorrelationContext.REQUEST_ID, "stale-version");
var response = handler.handleResponseStatus(
new ResponseStatusException(HttpStatus.CONFLICT, "Order was changed; refresh and retry"), request);
assertThat(response.getStatusCode().value()).isEqualTo(200);
assertThat(response.getBody().code()).isEqualTo(ResultCode.CONFLICT.code());
assertThat(response.getBody().message()).isEqualTo("Order was changed; refresh and retry");
assertThat(response.getBody().requestId()).isEqualTo("stale-version");
}
@Test
void missingControllerPathMapsToNotFoundInsteadOfInternalError() {
MockHttpServletRequest request = new MockHttpServletRequest();
var response = handler.handleNoResourceFound(
new NoResourceFoundException(org.springframework.http.HttpMethod.GET,
"api/platform/v1/last-leg/dispatches"), request);
assertThat(response.getStatusCode().value()).isEqualTo(200);
assertThat(response.getBody().code()).isEqualTo(ResultCode.NOT_FOUND.code());
}
private void paging(long page) {
}
}