Files
hms/docs/superpowers/specs/2026-04-26-test-coverage-strategy-design.md
iven 8cd65f7be5 docs: 测试覆盖率提升策略设计规格
主题 1 头脑风暴产出 — 测试覆盖率从 2% 提升到 80% 的分阶段路线图,
覆盖后端 27 个无测试 service、erp-ai 零测试、前端 138 文件仅 3 个测试。
采用分层渐进式方案,9 周分 4 Phase 完成。
2026-04-27 00:13:39 +08:00

306 lines
12 KiB
Markdown
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.
# 测试覆盖率提升策略设计规格
> 日期: 2026-04-26 | 状态: draft | 主题: 测试覆盖率 2% → 80%
## 1. 背景与目标
### 1.1 现状
HMS 健康管理平台当前测试覆盖极低:
- **后端**: 461 单元测试 + 54 集成测试,但 erp-health 34 entity 中 27 个 service 零单元测试erp-ai 整个 crate 零测试
- **前端**: 138 个源文件仅 3 个测试文件(覆盖率 2.2%API 层/Store 层/hooks 全部无测试
- **E2E**: Playwright 已配置(含 auth fixture但零测试用例
### 1.2 目标
- **全量覆盖率**: 后端所有层service/handler/entity/dto+ 前端所有层API/Store/hooks/页面)达到 80%
- **CI 增量门禁**: 新增/修改文件覆盖率 ≥ 80% 才允许合并
- **时间线**: 9 周分阶段完成
### 1.3 决策记录
| 决策 | 选择 | 理由 |
|------|------|------|
| 覆盖范围 | 全量 80% | 医疗场景需要全面质量保证 |
| CI 门禁 | 增量门禁 | 不阻塞现有开发,只要求新增代码 |
| 后端策略 | 集成测试为主Testcontainers | 最接近生产SeaORM mock 不成熟 |
| 整体方案 | 分层渐进式(方案 A | 按风险密度排序,与增量门禁配合 |
---
## 2. 后端测试策略
### 2.1 测试分层模型
```
┌─────────────────────────────────────────┐
│ Integration Tests (Testcontainers) │ ← 27 service + 16 handler
│ erp-server/tests/integration/ │
├─────────────────────────────────────────┤
│ Unit Tests (tokio::test / #[test]) │ ← validation/crypto/masking
│ 内联 #[cfg(test)] mod tests │
├─────────────────────────────────────────┤
│ Pure Function Tests │ ← DTO 转换、枚举、工具函数
│ 零依赖,毫秒级 │
└─────────────────────────────────────────┘
```
### 2.2 TestDb 基础设施增强
当前 `crates/erp-server/tests/integration/test_db.rs` 已有 `TestDb` struct。需要增强为
**TestApp struct** — 封装完整测试环境:
- TestDbPostgreSQL Testcontainer + 自动迁移)
- Axum Router与生产配置相同的路由
- AppStateDatabaseConnection + EventBus + Crypto
- HTTP 客户端(`reqwest::Client``tower::ServiceExt`
**TestFixture 工厂** — 预构建测试数据:
- `create_tenant(name)` → 创建租户 + 返回 TenantContext
- `create_user(tenant_id, role)` → 创建用户 + 返回 JWT
- `create_patient(tenant_id, ...)` → 创建患者档案
- `create_doctor(tenant_id, ...)` → 创建医生档案
- `create_schedule(tenant_id, doctor_id, ...)` → 创建排班
**并行隔离** — 每个测试使用独立的 `tenant_id`,支持并行执行。
### 2.3 Phase 分配
#### Phase 1: 高风险 ServiceWeek 1-2
| Service | 测试重点 | 估计测试数 |
|---------|---------|-----------|
| `points_service` | FIFO 积分消费、余额不足拒绝、并发消费安全性、签到积分 | 12 |
| `dialysis_service` | PII 字段加密存储、HMAC 索引查询、CRUD 完整性 | 8 |
| `alert_engine` | 规则评估逻辑、cooldown 检查、危急值触发 | 8 |
| `alert_rule_service` | 规则 CRUD、阈值验证、启用/禁用 | 6 |
| `device_reading_service` | 批量插入、降采样聚合、数据范围查询 | 8 |
#### Phase 2: 中风险 ServiceWeek 3-4
| Service | 测试重点 | 估计测试数 |
|---------|---------|-----------|
| `patient_service` | CRUD + 家属管理 + 标签管理 + 健康摘要 | 10 |
| `appointment_service` | 创建预约 CAS + 状态变更 + 取消释放额度 | 8 |
| `follow_up_service` | 状态机 6 种转换 + 任务分配 + 执行记录 | 8 |
| `consultation_service` | 会话 CRUD + 消息收发 + 状态变更 | 5 |
| `doctor_service` | CRUD + 排班关联 | 4 |
| erp-ai 基础测试 | 提示模板 CRUD + 分析记录 + 使用统计 | 12 |
#### Phase 3: 低风险 Service + Handler + DTOWeek 5-6
| Service | 测试重点 | 估计测试数 |
|---------|---------|-----------|
| `article_service` | CRUD + 审核状态流转 | 5 |
| `article_category_service` | CRUD + 层级管理 | 4 |
| `article_tag_service` | CRUD + 关联管理 | 3 |
| `offline_event_service` | CRUD + 报名管理 | 4 |
| `consent_service` | CRUD + 签署状态 | 3 |
| `diagnosis_service` | CRUD + ICD 编码验证 | 3 |
| `stats_service` | 各维度统计查询正确性 | 5 |
| `health_data_service` | 体征/化验/体检 CRUD + 趋势计算 | 8 |
| handler 层 | 16 个 handler 的 HTTP 层测试 | 16 |
| DTO 转换 | 请求/响应 DTO 序列化/反序列化 | 10 |
### 2.4 测试命名规范
```
test_{功能}_{场景}_{预期结果}
例: test_points_consume_fifo_balance_deducted
test_patient_create_duplicate_id_card_returns_conflict
test_appointment_create_exceeds_max_returns_error
test_alert_engine_cooldown_prevents_duplicate
test_dialysis_create_pii_fields_encrypted
```
### 2.5 测试文件组织
```
crates/erp-server/tests/integration/
├── test_db.rs # TestDb + TestApp 基础设施
├── test_fixture.rs # TestFixture 工厂
├── auth_tests.rs # 已有
├── workflow_tests.rs # 已有
├── health_patient_tests.rs # 已有(扩展)
├── health_pii_encryption_tests.rs # 已有(保持)
├── health_appointment_tests.rs # 已有(扩展)
├── health_points_tests.rs # 新增
├── health_dialysis_tests.rs # 新增
├── health_alert_tests.rs # 新增
├── health_device_reading_tests.rs # 新增
├── health_follow_up_tests.rs # 新增
├── health_consultation_tests.rs # 新增
├── health_doctor_tests.rs # 新增
├── health_article_tests.rs # 新增
├── health_stats_tests.rs # 新增
├── health_data_tests.rs # 新增
├── ai_prompt_template_tests.rs # 新增
├── ai_analysis_tests.rs # 新增
└── ai_usage_tests.rs # 新增
```
---
## 3. 前端测试策略
### 3.1 测试分层模型
```
┌─────────────────────────────────────────┐
│ E2E Tests (Playwright) │ ← 5 个关键用户流程
├─────────────────────────────────────────┤
│ Page Integration Tests │ ← 8 个核心页面
│ vitest + @testing-library/react │
├─────────────────────────────────────────┤
│ Store/Hook Unit Tests │ ← 5 stores + 3 hooks
│ vitest │
├─────────────────────────────────────────┤
│ API Layer Tests │ ← client.ts + 7 health API
│ vitest + MSW │
└─────────────────────────────────────────┘
```
### 3.2 测试工具链
| 工具 | 用途 | 状态 |
|------|------|------|
| Vitest | 单元测试 + 组件测试 | ✅ 已配置 |
| @testing-library/react | 组件渲染测试 | ✅ 已有 |
| MSW (mock-service-worker) | API mock | ❌ 需新增 |
| Playwright | E2E 测试 | ✅ 已配置 + auth fixture |
| @vitest/coverage-v8 | 覆盖率报告 | ❌ 需新增 |
### 3.3 MSW Mock 策略
建立 `apps/web/src/test/` 目录:
```
apps/web/src/test/
├── setup.ts # 测试全局 setup已有需增强
├── mocks/
│ ├── handlers.ts # 统一 API mock handlers
│ ├── server.ts # MSW server setup
│ ├── browser.ts # MSW browser setupE2E 用)
│ └── fixtures/ # 测试数据 JSON
│ ├── patients.json
│ ├── appointments.json
│ └── ...
└── utils/
├── render-with-providers.tsx # 包含 Router + Store 的 render wrapper
└── wait-for.ts # 异步等待工具
```
### 3.4 Phase 4: 前端补测Week 7-9
#### Week 7: API 层 + Store 层
| 文件 | 测试重点 | 测试数 |
|------|---------|--------|
| `api/client.ts` | token 主动刷新、401 被动刷新、并发请求队列、缓存命中/过期 | 12 |
| `api/health/patients.ts` | CRUD 参数正确性、分页参数、错误映射 | 5 |
| `api/health/appointments.ts` | 创建预约参数、状态变更、排班查询 | 4 |
| `api/health/*.ts`(其余 5 个) | CRUD 基础覆盖 | 10 |
| `stores/auth.ts` | login/logout/refresh 权限列表 | 5 |
| `stores/plugin.ts` | 插件列表加载、菜单生成、去重 | 5 |
| `stores/health.ts` | 名称缓存、批量解析 | 3 |
| `stores/message.ts` | SSE 连接、未读计数、乐观更新 | 4 |
#### Week 8: Hooks + 核心页面组件
| 文件 | 测试重点 | 测试数 |
|------|---------|--------|
| `hooks/useApiRequest.ts` | loading/error 状态、重试、取消 | 5 |
| `hooks/usePaginatedData.ts` | 分页加载、刷新、参数变更 | 4 |
| `hooks/usePermission.ts` | 权限检查、admin 跳过 | 3 |
| `pages/health/PatientList.tsx` | 列表渲染、搜索、新建弹窗 | 5 |
| `pages/health/AppointmentList.tsx` | 列表渲染、新建预约、状态变更 | 5 |
| `pages/health/ConsultationList.tsx` | 列表渲染、行点击导航 | 3 |
| `pages/health/FollowUpTaskList.tsx` | 列表渲染、状态筛选 | 3 |
| `pages/health/StatisticsDashboard.tsx` | 数据加载、卡片渲染 | 3 |
#### Week 9: Playwright E2E
| 测试场景 | 覆盖流程 |
|---------|---------|
| 患者管理 CRUD | 登录 → 创建患者 → 编辑 → 查看 → 搜索 |
| 预约流程 | 选医生 → 查排班 → 创建预约 → 取消预约 |
| 随访任务 | 创建随访 → 分配 → 执行 → 完成 |
| 咨询流程 | 创建咨询 → 发送消息 → 关闭 |
| 数据统计 | 查看统计仪表板 → 导出 |
---
## 4. CI 门禁策略
### 4.1 增量覆盖率门禁
**后端** — 使用 `cargo-llvm-cov`:
```bash
cargo llvm-cov --fail-under-lines=80 --modified-files-only
```
**前端** — 使用 `@vitest/coverage-v8`:
```bash
cd apps/web && pnpm vitest run --coverage --changed=HEAD~1
```
### 4.2 CI 流水线
```yaml
# PR 提交时
on: pull_request
jobs:
backend-test:
runs-on: ubuntu-latest
steps:
- cargo test --workspace
- cargo llvm-cov --fail-under-lines=80 --modified-files-only
frontend-test:
runs-on: ubuntu-latest
steps:
- cd apps/web && pnpm test:ci
- pnpm vitest run --coverage --changed=origin/main
# E2E: 仅 main 分支或手动触发
e2e-test:
if: github.ref == 'refs/heads/main'
steps:
- pnpm exec playwright test
```
### 4.3 里程碑
| 时间点 | 门禁要求 |
|--------|---------|
| Week 6 后 | 后端增量门禁上线 |
| Week 9 后 | 前端增量门禁上线 |
| Week 12 后 | 全量覆盖率报告 + 目标复盘 |
---
## 5. 风险与缓解
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| Testcontainers Windows 启动慢 | 开发体验差 | CI 用 Linux runner本地开发串行测试预热 Docker 镜像 |
| MSW mock 与真实 API 不一致 | 测试通过但生产出错 | 关键流程 E2E 兜底;从 OpenAPI spec 生成 handlers |
| 补测与功能开发冲突 | merge conflict | 测试文件独立于业务代码;集成测试集中在 erp-server/tests/ |
| 前端 9 周达不到 80% | 延期 | 接受"后端 80% + 前端 60%"作为 Phase 1 目标 |
| erp-ai 依赖外部 AI API | 测试不稳定 | mock 外部 AI 调用,仅测试内部逻辑 |
---
## 6. 成功指标
| 指标 | Week 6 目标 | Week 9 目标 |
|------|------------|------------|
| 后端 service 测试覆盖率 | ≥ 80% | ≥ 85% |
| 后端全量测试覆盖率 | ≥ 70% | ≥ 80% |
| 前端 API+Store 测试覆盖率 | - | ≥ 80% |
| 前端全量测试覆盖率 | - | ≥ 60% |
| E2E 测试用例数 | - | ≥ 5 |
| CI 增量门禁 | 后端上线 | 前后端上线 |