Files
hms/docs/superpowers/specs/2026-04-26-test-coverage-strategy-design.md
iven 5b81a0051f docs: 修正测试策略 spec 的事实性错误
修正 spec review 发现的问题:
- C-1: TestDb 实际是本地 PostgreSQL 隔离,非 Testcontainers
- C-2: E2E 已有 4 spec/10 测试,非零测试
- 补充 6 个遗漏的 service(alert/daily_monitoring/critical_value_threshold 等)
- 增加 Phase 0 基础设施搭建
- 修正 CI 配置(增加 PostgreSQL service、验证链)
- 补充 5 个遗漏风险项和回退策略
- 统一"全量 80%"目标的准确含义
2026-04-27 00:21:02 +08:00

17 KiB
Raw Blame History

测试覆盖率提升策略设计规格

日期: 2026-04-26 | 状态: draft | 主题: 测试覆盖率 2% → 80%

1. 背景与目标

1.1 现状

HMS 健康管理平台当前测试覆盖极低:

  • 后端: 约 461 单元测试 + 54 集成测试wiki/testing.md 记录 93 个,差距因统计口径不同 — 此处含所有 crate 的 #[test]/#[tokio::test] 标记),但 erp-health 34 entity 中 27 个 service 零单元测试erp-ai 整个 crate 零测试
  • 前端: 138 个源文件仅 3 个单元测试文件(覆盖率 2.2%API 层/Store 层/hooks 全部无测试
  • E2E: Playwright 已配置(含 auth fixture apps/web/e2e/auth.fixture.ts),已有 4 个 spec、10 个测试用例login/users/plugins/tenant-isolation但健康模块零 E2E 覆盖

1.2 目标

  • 全量覆盖率: 后端所有层service/handler/entity/dto+ 前端所有层API/Store/hooks/页面)达到 80%
  • CI 增量门禁: 新增/修改文件覆盖率 ≥ 80% 才允许合并
  • 时间线: 9 周分阶段完成

1.3 决策记录

决策 选择 理由
覆盖范围 全量 80% 医疗场景需要全面质量保证
CI 门禁 增量门禁 不阻塞现有开发,只要求新增代码
后端策略 集成测试为主(本地 PostgreSQL 隔离数据库) 最接近生产SeaORM mock 不成熟;当前 TestDb 已连接本地 PostgreSQL
整体方案 分层渐进式(方案 A 按风险密度排序,与增量门禁配合

2. 后端测试策略

2.1 测试分层模型

┌─────────────────────────────────────────┐
│  Integration Tests (本地 PG 隔离)       │  ← 30 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连接本地 PostgreSQL 创建临时数据库(不依赖 Docker/Testcontainers与开发环境一致。需要增强为

TestApp struct — 封装完整测试环境:

  • TestDb本地 PostgreSQL 隔离数据库 + 自动迁移)
  • Axum Router仅注册 erp-health 模块,减少启动开销)
  • AppStateDatabaseConnection + EventBus + Crypto使用测试专用密钥
  • HTTP 客户端(使用 tower::ServiceExt,无需真实 TCP 监听,测试更快速稳定)

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 0: 测试基础设施搭建Week 1 前 2 天)

任务 产出
TestApp struct 实现 TestDb + Axum Router + AppState + tower ServiceExt 客户端
TestFixture 工厂 create_tenant/create_user/create_patient/create_doctor 工厂函数
@vitest/coverage-v8 安装配置 前端覆盖率报告可用
MSW v2 初始配置 handlers.ts + server.ts 基础框架
cargo-llvm-cov 安装验证 后端增量覆盖率命令可用(配合自定义 git diff 脚本过滤)

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
alert_service 告警 CRUD、状态变更、批量确认 5
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
daily_monitoring_service 日常监测 CRUD + 阈值校验 4
critical_value_threshold_service 阈值 CRUD + 范围校验 3
stats_service 各维度统计查询正确性 5
health_data_service 体征/化验/体检 CRUD + 趋势计算 8
trend_service 已有 14 个内联测试,补充集成测试 3
masking 已有 14 个内联测试,保持 0
handler 层 16 个 handler 的 HTTP 层测试 16
DTO 转换 请求/响应 DTO 序列化/反序列化 10

注:所有健康模块集成测试集中在 erp-server/tests/integration/ 下,通过 cargo test -p erp-server 运行。erp-health 的内联单元测试validation/crypto/masking/trend通过 cargo test -p erp-health 运行。

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健康模块专项

已有 4 个基础 ERP speclogin/users/plugins/tenant-isolation10 个测试。Week 9 新增健康模块 E2E

测试场景 覆盖流程
患者管理 CRUD 登录 → 创建患者 → 编辑 → 查看 → 搜索
预约流程 选医生 → 查排班 → 创建预约 → 取消预约
随访任务 创建随访 → 分配 → 执行 → 完成
咨询流程 创建咨询 → 发送消息 → 关闭
数据统计 查看统计仪表板 → 导出

E2E 测试依赖前后端同时启动。Playwright 配置了 webServer.command: pnpm dev(前端),但需确保后端服务已运行。在 CI 中需同时启动后端(cargo run+ 前端(pnpm dev)。


4. CI 门禁策略

4.1 增量覆盖率门禁

后端 — 使用 cargo-llvm-cov 配合自定义脚本:

# 安装: cargo install cargo-llvm-cov
# 全量测试
cargo llvm-cov --workspace --lcov --output-path lcov.info
# 增量检查(自定义脚本,基于 git diff 过滤变更文件)
cargo llvm-cov --workspace --json | python3 scripts/coverage-diff-check.py --threshold=80

注:cargo-llvm-cov 原生不支持 --modified-files-only需要自定义脚本实现增量过滤。Phase 0 中需验证可行性。

前端 — 使用 @vitest/coverage-v8:

cd apps/web && pnpm vitest run --coverage
# 增量检查通过自定义脚本过滤变更文件

4.2 CI 流水线

前置条件: 项目当前无 CI 配置(.github/workflows/ 不存在Phase 0 需创建初始 workflow。

# .github/workflows/test.yml
on: pull_request
jobs:
  backend-test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: test_password
          POSTGRES_DB: erp_test
        ports: ["5432:5432"]
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    env:
      ERP__DATABASE__URL: postgres://postgres:test_password@localhost:5432/erp_test
      ERP__JWT__SECRET: ci-test-jwt-secret
    steps:
      - uses: actions/checkout@v4
      - cargo test --workspace
      - cargo llvm-cov --workspace --json

  frontend-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - cd apps/web && pnpm install && pnpm test:ci

  # E2E: 仅 main 分支或手动触发
  e2e-test:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    services:
      postgres: # 同上
    steps:
      - cargo run &  # 后台启动后端
      - cd apps/web && pnpm dev &  # 后台启动前端
      - sleep 10  # 等待服务就绪
      - pnpm exec playwright test

CI 流水线需包含 CLAUDE.md 要求的完整验证链:cargo checkcargo testcargo clippypnpm build

4.3 里程碑

时间点 门禁要求
Week 6 后 后端增量门禁上线
Week 9 后 前端增量门禁上线
Week 12 后 全量覆盖率报告 + 目标复盘

5. 风险与缓解

风险 影响 缓解措施
本地 PG 并行测试连接池耗尽 多个 TestDb 实例同时创建可能超限 限制并行度 --test-threads=2CI 环境单独配置
测试 panic 后残留临时数据库 长期累积占用磁盘 TestApp Drop 时强制清理;定期脚本清理 test_* 前缀数据库
并行迁移竞争 多个 TestDb 同时 Migrator::up 每个测试用独立数据库名UUID互不影响
MSW mock 与真实 API 不一致 测试通过但生产出错 关键流程 E2E 兜底MSW handlers 从 OpenAPI spec 自动生成
补测与功能开发冲突 merge conflict 测试文件独立于业务代码;集成测试集中在 erp-server/tests/
前端 9 周达不到 80% 延期 接受"后端 80% + 前端 60%"作为 Phase 1 目标,前端在后续迭代持续补齐
erp-ai 依赖外部 AI API 测试不稳定 mock 外部 AI 调用,仅测试内部逻辑
MSW 与 axios 缓存 adapter 冲突 mock 拦截异常 MSW 在 service worker 层拦截,绕过 axios adapter需验证兼容性
E2E 测试后端未启动失败 测试环境不可用 CI 中先启动后端再运行 E2E本地用 dev.ps1 一键启动
目标不可达时无回退方案 计划失控 每 Phase 结束复盘覆盖率;如 Phase 2 后仅 50%,则缩减 Phase 3 范围或延长时间线

6. 成功指标

指标 Week 6 目标 Week 9 目标
后端 service 测试覆盖率 ≥ 80% ≥ 85%
后端全量测试覆盖率 ≥ 70% ≥ 80%
前端 API+Store 测试覆盖率 - ≥ 80%
前端全量测试覆盖率 - ≥ 60%Phase 1 目标,后续迭代持续提升到 80%
E2E 测试用例数(健康模块) - ≥ 5 个新 spec
CI 增量门禁 后端上线 前后端上线

目标澄清: "全量 80%"是最终目标。Phase 19 周)的目标是后端 80% + 前端 60%,前端剩余部分在后续迭代中持续补齐。每 Phase 结束后复盘实际覆盖率,必要时调整计划。