"""全局异常处理器单元测试。 重点验证校验错误的文案压缩逻辑:FastAPI 默认返回 422 与 detail 数组, 本项目需映射为 400 与单行中文提示。 """ from fastapi.exceptions import RequestValidationError from app.core.constants import CODE_BAD_REQUEST from app.core.exception_handlers import _build_response, _format_validation_errors class TestFormatValidationErrors: """校验错误文案压缩。""" def test_包含字段名与原始说明(self) -> None: exc = RequestValidationError( [{"loc": ("body", "username"), "msg": "Field required", "type": "missing"}] ) assert _format_validation_errors(exc) == "参数错误:username Field required" def test_去掉来源前缀只保留字段路径(self) -> None: exc = RequestValidationError( [ { "loc": ("query", "pageNum"), "msg": "Input should be greater than 0", "type": "greater_than", } ] ) assert "query" not in _format_validation_errors(exc) assert "pageNum" in _format_validation_errors(exc) def test_多个错误时只取第一条(self) -> None: exc = RequestValidationError( [ {"loc": ("body", "a"), "msg": "错误甲", "type": "missing"}, {"loc": ("body", "b"), "msg": "错误乙", "type": "missing"}, ] ) message = _format_validation_errors(exc) assert "错误甲" in message assert "错误乙" not in message def test_错误列表为空时兜底(self) -> None: assert _format_validation_errors(RequestValidationError([])) == "参数错误" class TestBuildResponse: """统一响应构造:HTTP 状态码与响应体 code 必须一致。""" def test_状态码与响应体code一致(self) -> None: response = _build_response(CODE_BAD_REQUEST, "参数错误") assert response.status_code == CODE_BAD_REQUEST import json body = json.loads(response.body) assert body["code"] == CODE_BAD_REQUEST assert body["message"] == "参数错误" assert body["data"] is None