---
name: test-backend
description: 当用户要求后端测试（集成测试）编写、修复、执行或定位失败时使用。依据后端代码、API 文档与用户场景文档；不处理 E2E。
---

# 后端测试技能（test-backend）

## 项目概览入口
- 项目定位、技术栈与目录入口请阅读：`../references/project-overview.md`

## 适用范围
- **集成测试为主**：Controller → Service → 真实数据库，验证完整 API 请求-响应链路。
- 不写单元测试（除非有复杂纯计算逻辑，如权重校验算法、分数区间重叠检测）。
- 不做 E2E（E2E 走 test-frontend，Playwright MCP）。

## 集成测试两层结构

| 层次 | 目标 | 驱动源 | 断言方式 |
|------|------|--------|---------|
| **L1a API 契约测试** | 每个端点能跑通，返回结构正确 | `07-api.md` 端点清单 | 状态码 + 字段存在 + 类型 |
| **L1b 业务规则测试** | 每条业务规则的计算/流转/隔离正确 | `01-prd.md` + `04-state-machine.md` | **具体数值 + 状态变化 + 数据隔离** |

L1a 验证"API 能跑通"，L1b 验证"业务规则正确"。只有 L1a 会漏掉加权分算错、组织没隔离、状态没流转等问题。

## 工作流

### 阶段一：文档-代码对齐验证（写测试之前必须完成）

1) 读取模块文档与契约：`01-prd.md`、`07-api.md`、`09-test-scenarios.md`（以 07 中接口数量汇总与按域清单为覆盖基准）。

2) **逐端点验证后端代码与 07-api.md 的字段级一致性**（阻断性步骤）：
   - 对每个 In-scope 端点，读取后端 controller 的实际返回值
   - 对照 `07-api.md` 逐字段检查：字段名、类型、必填性、嵌套结构
   - 输出"字段级一致性报告"
   - **发现不一致必须先修复后端代码，再继续**

3) **检查 API 契约与前端一致性**（双向检查）：
   - 返回值 → 前端 interface、请求体 → 前端实际发送
   - 参考：`.agents/skills/backend-main/references/api-contract-checklist.md`

### 阶段二：测试用例编写

4) **L1a**：以 07-api.md 为基准，为每个端点生成测试，断言逐字段对照文档。位置：`testing/backend/integration/{module}/`

4b) **L1b**：以 01-prd.md + 04-state-machine.md 为基准，正向推导业务规则测试。详见 `references/l1b-business-rules-guide.md`。

5) 执行前校验：L1a 端点覆盖率 ≥ 90%，L1b 业务规则覆盖率对照表。

### 阶段二½：硬阻断校验 Gate（测试执行前必须通过）

**在执行测试之前，必须逐项自查以下 checklist 并输出结果。任何一项 FAIL 则阻断执行，先补齐再继续。**

#### Gate 1：多角色覆盖验证
```bash
# 测试文件中必须出现至少 3 种角色的 token 创建
# 搜索 Employee/普通用户角色
grep -c 'Employee\|createTestUser\|empToken\|employeeToken' <测试文件>
# 搜索 Leader/Manager 角色
grep -c 'Leader\|Manager\|leaderToken\|managerToken' <测试文件>
```
- [ ] Administrator 角色：存在 → PASS
- [ ] Employee 角色：存在且有权限边界测试（自己 200 / 别人 403）→ PASS
- [ ] Leader/Manager 角色：存在且有上下级数据隔离测试 → PASS

**FAIL 时的修复方式**：在测试文件中增加 `describe('多角色权限验证')` 块，至少覆盖：
- Employee 访问自己的 KPI/结果 → 200
- Employee 访问他人的 KPI/结果 → 403
- Leader 查看下属数据 → 200，查看非下属 → 403/空

#### Gate 2：端点全覆盖验证
```bash
# 从 controller 提取所有 @Get/@Post/@Put/@Patch/@Delete 路由
# 与测试文件中的 HTTP 调用做 diff
grep -E '@(Get|Post|Put|Patch|Delete)\(' backend/src/modules/<module>/controllers/*.ts
grep -E '\.(get|post|put|patch|delete)\(' <测试文件>
```
- [ ] 输出"未覆盖端点列表"
- [ ] 未覆盖端点数 = 0 → PASS；> 0 → 列出并补齐

#### Gate 3：状态推进副作用验证
```
对每个状态推进测试（publish/start-xxx/complete 等），检查 it 块内是否包含：
- 主表状态断言（必须有）
- 关联表副作用断言（按 §3 表格要求）
```
- [ ] 每个状态推进 it 块内含关联表查询断言 → PASS
- [ ] 缺少副作用断言的 it 块列表为空 → PASS

#### Gate 4：skip/todo 审计
```bash
grep -n 'it\.skip\|xit\|xdescribe\|TODO\|FIXME' <测试文件>
```
- [ ] 无 `it.skip` 或每个 skip 有明确的 issue 编号和修复计划 → PASS
- [ ] 有无理由的 skip → FAIL，必须修复或补充说明

**输出格式**（必须在测试报告的"执行前校验"段落展示）：
```
## 执行前 Gate 校验
| Gate | 结果 | 详情 |
|------|------|------|
| G1 多角色覆盖 | ✅ PASS / ❌ FAIL | Admin ✓ Employee ✓ Leader ✓ |
| G2 端点全覆盖 | ✅ PASS / ❌ FAIL | 87/87 覆盖 |
| G3 副作用验证 | ✅ PASS / ❌ FAIL | 6/6 状态推进含副作用断言 |
| G4 skip 审计 | ✅ PASS / ❌ FAIL | 0 个无理由 skip |
```

### 阶段三：执行与报告

6) 复用已有测试辅助：`testing/backend/helpers/`
7) 执行：`cd testing && npm run test:backend:integration`
8) 报告格式见 `references/test-report-format.md`

## 断言核心要求

- **严格以 07-api.md 为准**：断言逐字段对照文档，不能只检查 `toHaveProperty('id')`
- 状态转换 API 返回完整资源字段
- 请求体断言：必填字段缺失时返回正确错误码
- 禁止跳过文档中定义的端点
- 参考检查清单：`.agents/skills/backend-main/references/api-contract-checklist.md`

## 必须覆盖的通用测试维度

以下规则适用于**所有模块**，源自实际项目中多次遗漏的教训。

### 1. 多角色覆盖（防止"只用 admin 测"盲区）

每个模块的 L1 集成测试必须至少用 **3 个角色**执行核心 API：

| 角色 | 目的 | 典型断言 |
|------|------|---------|
| Administrator | 验证功能正确性 | 200 + 正确数据 |
| Employee（普通用户） | 验证权限边界 | 自己的数据 200，别人的 403 |
| Leader/Manager | 验证上下级关系 | 能看到下属，看不到非下属 |

**反模式**：全部测试用 admin token → 权限装饰器 bug 永远发现不了。

### 2. 运行时契约验证（防止"DTO whitelist 静默丢弃"）

L1a 契约测试不能只检查"字段名存在"，必须验证**关键字段在有数据时非空**：

```
// ❌ 只检查字段存在
expect(body).toHaveProperty('dependentUserId');

// ✅ 验证有数据时非空
const itemWithDep = body.items.find(i => /* 已设置依赖的 */);
expect(itemWithDep.dependentUserId).not.toBeNull();
expect(itemWithDep.dependentUser.displayName).toBeTruthy();
```

特别注意 NestJS `ValidationPipe({ whitelist: true })` 会**静默丢弃** DTO 中未声明的字段。前端传了但后端没收到 → API 返回 200 但数据没变。

### 3. 写操作副作用验证（防止"状态推了但关联表没变"）

每个状态推进或写操作的测试，除了验证主表状态变化，**必须验证关联表的副作用**：

| 操作 | 主表断言 | 必须追加的副作用断言 |
|------|---------|-------------------|
| 发布周期 | status = GOAL_SETTING | — |
| 推进到校准 | status = CALIBRATING | `performance_result` 表有记录 |
| 推进到确认 | status = CONFIRMING | result.isPublished = true |
| 设置依赖人 | 200 | `kpi_dependency` 表有记录 |
| 员工申诉 | confirmStatus = APPEALED | appealReason 非空 |

### 4. 种子关系完整性检查（防止"用户存在但关系缺失"）

L1c 数据质量检查必须验证测试用户之间的**业务关系**，而不仅仅是"用户存在"：

```sql
-- 验证 manager 链路：test.dev1 → test.lead1 → itadmin
SELECT u.username, m.username as manager
FROM platform_iam.users u
JOIN corp_hr.user_departments ud ON ud.user_id = u.id AND ud.left_at IS NULL
JOIN platform_iam.users m ON m.id = ud.manager_id
WHERE u.username IN ('test.dev1', 'test.lead1');
```

如果关系缺失 → 团队审批、经理评分、下属列表等功能全部空白。

## ⛔ 禁止为了通过测试而修改断言（核心禁令）

**当集成测试失败时，必须按以下决策树处理，禁止直接修改断言来让测试通过：**

```
测试失败
  ├─ 先读 07-api.md，找到对应端点的字段定义
  ├─ 再读后端实现（service/controller），确认实际返回结构
  ├─ 判断：
  │   ├─ 后端实现 ≠ 07-api.md  →  修后端，不修测试
  │   ├─ 测试断言 ≠ 07-api.md  →  修测试，使其与文档一致
  │   └─ 测试夹具/fixture 与当前 schema 不兼容（如必填字段新增）→  修 fixture，属于合理适配
  └─ 禁止：在未确认文档依据的情况下，直接修改断言路径以匹配后端的错误返回
```

**判断标准**：

| 修改类型 | 是否允许 | 说明 |
|---------|---------|------|
| 修复后端实现使其与 07-api.md 一致 | ✅ 必须 | 后端是错的，不是测试是错的 |
| 修复 fixture（test setup）跟上 schema 演进 | ✅ 合理 | 如新增必填关联字段 |
| 修改断言路径使其匹配文档定义 | ✅ 允许 | 测试之前写错了，要改对 |
| 修改断言路径以匹配与文档不符的后端返回 | ⛔ 禁止 | 这是为通过测试而让步 |
| 删除或注释掉断言以避免失败 | ⛔ 禁止 | 掩盖问题而非修复 |

**常见错误示例（必须识别并拒绝）**：
- 将 `expect(body.avgScore).toBeDefined()` 改为 `expect(body.kpiStats.avgScore).toBeDefined()`，仅因为后端实际返回了 `kpiStats.avgScore`——如果 07-api.md 定义 `avgScore` 在顶层，则必须修后端
- 将 `expect(body.companyReport.avgScore)` 改为 `expect(body.data.avgScore)`，仅因为后端多包了一层 `data`——如果文档无此嵌套，则修后端

## 参考（按需加载）

- `references/l1b-business-rules-guide.md`（L1b 业务规则覆盖与断言要求）
- `references/regression-and-isolation-rules.md`（回归防护、变更分析、数据隔离）
- `references/test-report-format.md`（报告格式与自动化脚本）
- `references/backend-testing-core.md`
- `references/backend-testing-checklist.md`
- `references/best-practices.md`
- `references/document-sync-checklist.md`
- `references/test-strategy-six-layers.md`（三层测试策略）
- `references/testing-standards.md`（测试总规范，原 docs/standards/07-testing）
