CI E2E (live stack) 在 main@63c18d8 上失败:test_appointment_concurrent_safety 并发「用户取消」与「运营确认」得到 [200, 500]。根因是 ServiceAppointmentService 四处状态/权限守卫抛裸 RuntimeException,GlobalExceptionHandler 无对应映射, 只能兜底成 HTTP 500 —— 「预约不存在」「状态不允许」「越权」被报成服务端故障。 改动: - ServiceAppointmentService:四处守卫改用 BusinessException + ApiResponseCode (不存在→404 NOT_FOUND,越权→403 FORBIDDEN,状态冲突→409 REDUNDANT_OPERATION)。 - ReferralService.confirmReferral:同一家族的四条守卫同样收敛(预约/报名的 不存在、越权、非转介类型)。 - tests/e2e/service_appointment_test.py:把 3 处 `!= 200` 的弱断言收紧为 4xx。 弱断言会把 500 当成「越权被拒」放行 —— 这正是该缺陷长期未被发现的原因, 此前只有并发用例的 `< 500` 断言咬了它一口。 - ServiceAppointmentOwnerGuardTest:新增「终态不可再确认/取消」「预约不存在」 用例,并把越权断言从 RuntimeException 收紧到具体业务码(403)。 验证: - 定向后端测试 35 passed(ServiceAppointment* / MatchmakerReferralPhase13Test)。 - 本机真实栈(重建 backend 镜像):service_appointment_test.py 8/8、全量 E2E 65 passed。 - 负向注入(把守卫改回裸 RuntimeException):2 例精准变红,工作区哈希前后一致。
测试基础设施
测试目录结构
tests/
├── invariants/ # 核心不变量测试(每次CI必跑)
│ ├── INV-001_Required不可自动放宽.test.ts
│ ├── INV-002_未Mutual不可聊天.test.ts
│ ├── INV-003_Block后双方不可互动.test.ts
│ ├── INV-004_双向并发Like只创建一个Match.test.ts
│ ├── INV-005_Activity最后一个名额不可超卖.test.ts
│ ├── INV-006_单向活动意向不可泄露.test.ts
│ ├── INV-007_红娘不能替用户Like.test.ts
│ ├── INV-008_非授权Operator不能读取身份证.test.ts
│ ├── INV-009_非案件上下文不能读取聊天.test.ts
│ └── INV-010_跨Organization不能越权.test.ts
├── unit/ # 单元测试
├── integration/ # 集成测试
├── api/ # API 测试
├── permission/ # 权限测试
├── concurrency/ # 并发测试
└── e2e/ # 端到端测试
Phase 01 测试骨架
每个测试文件至少包含:
- 测试描述
- 前置条件
- 操作步骤
- 预期结果
- 断言
运行测试
# Backend 单元测试
cd backend
./mvnw test
# Backend 集成测试
./mvnw verify
# Admin Web 构建检查
cd admin-web
pnpm build
# Miniapp 编译检查
cd miniapp
npx tsc --noEmit