# 测试规范 > 定位:改动必测、测试类型与覆盖、验证证据、根因判定纪律;独立评审与验收入口见 21-评审与验收规范.md。TDD 完整方法论见技能 `.claude/skills/tdd`、`test-driven-development`;根因诊断见 `.claude/skills/systematic-debugging`、`diagnosing-bugs`。 ## 负面清单(Do Not) - [禁止] 改动不跑测试就宣称完成 - [禁止] 测试失败时绕过/跳过测试提交代码 - [禁止] 每个测试文件各自造轮子(应复用测试辅助代码) - [禁止] 测试依赖真实远程生产数据 - [禁止] seed 脚本面向生产环境执行 ## 必须规则 1. **[必须] 改动必测**:新增功能、修复 bug、数据结构变更,必须补充或更新对应测试;测试通过才算完成(DoD 之一)。 2. **[必须] 测试类型与覆盖**:前端组件行为测试(而非实现细节)+ 服务测试(mock HTTP);后端 services 单元测试 + routes/controllers 集成测试(supertest);关键链路(登录鉴权/支付计费/数据删除)必须有测试覆盖;新功能覆盖率不得低于项目现有基线。 3. **[必须] 验收可追溯**:PRD 验收标准编号化(AC-01、AC-02...),测试用例在描述中引用验收标准编号,实现需求可追溯(需求-测试矩阵见 docs/04-quality)。 4. **[必须] 测试代码封装规范**(防重复造轮子):前端测试辅助统一放 src/testing/(mocks/fixtures/helpers),后端统一放 server/__tests__/helpers/(工具函数/公共断言);Mock 数据用工厂函数生成(MockUserFactory.create({...})),禁止散落对象字面量;测试文件与被测文件一一对应(user.service.ts → user.service.spec.ts),命名统一。 5. **[必须] 测试代码质量**:测试代码同样遵循 prettier/命名规范;允许 describe/it/expect 专用约定。 6. **[必须] 测试环境隔离**:测试跑独立 .env.test,不依赖远程生产数据;时间类边界用 fake timers,不 mock 无法可靠模拟的系统边界。 7. **[必须] 测试数据管理**:测试数据与 seed 脚本禁止面向生产;测试后清理,不留脏数据。集成测试多轮运行会累积历史数据(如把种子数据挤出分页首页)——beforeAll 必须清理测试库;beforeDelete 云函数拦截一切物理删除(含 masterKey)时 Parse API 无法清库,专用测试库可用原生 SQL 直删并注释原因(仅限测试库)。 8. **[必须] 测试命令**:前端 pnpm test(jest-preset-angular)、后端 pnpm test(jest + supertest);e2e 测试独立命令。 9. **[必须] 回归保障**:修复 bug 时必须先写复现该 bug 的失败测试,再修复到通过,防止回归。 10. **[必须] ESM 依赖的集成测试用子进程方案**:被测服务动态导入纯 ESM 依赖(如 parse-server 8 的 @parse/push-adapter)时,jest 的 CJS vm 沙箱无法加载(ERR_REQUIRE_ESM)——集成测试必须 spawn 启动真实服务进程(测试端口用 PORT 环境变量覆盖,如 3901),supertest 以 URL 断言;被测服务自身 SDK 回连地址(selfParseServerUrl)必须指向自身进程端口,禁止指向外部服务。 11. **[必须] 验证证据四类**(无证据 = 未完成,禁止"看起来对就行"):命令+输出(命令文本+退出码+关键输出片段)/测试报告(用例数/通过数/失败用例清单)/截图+步骤(UI/浏览器验证:截图+操作步骤+环境版本)/API 响应(状态码+响应体+请求参数)。 12. **[必须] 根因判定门禁(先判后修)**:修复 bug 前必须先回答这是根因还是打补丁——修复能否消除所有同类触发路径?若只挡当前症状(如加 if (x) return)而未说明为何进入该状态即为补丁,必须继续追问上游成因;AI 推断的根因只能作为候选假设,每个候选根因至少匹配一种验证证据(日志/堆栈对齐、复现测试、源码路径追踪、环境对比、官方文档),证据不足时输出「最可能原因+待验证动作」,不得写成已确认根因;补丁式修复必须标注「补丁风险」并给出上游排查动作。 13. **[必须] 证伪门禁**:关键算法/关键结论交付前构造反例尝试推翻——空值/空集合、边界值(0/1/最大/负数)、并发竞态、超大输入、自环互环(图/状态机算法);构造不出反例才允许交付。跑通 ≠ 正确,happy-path 通过 ≠ 无缺陷,禁止用弱用例通过冒充正确。 14. **[必须] jest 30 + ts-jest + 纯 ESM 依赖**:parse-server/fmode-ng 为纯 ESM——jest 30 已移除 `--experimental-vm-modules` CLI 标志,须经 NODE_OPTIONS 传入(测试脚本 `set NODE_OPTIONS=--experimental-vm-modules&& jest --runInBand`);ts-jest(module commonjs)会把 `import()` 降级为 `require()`,动态加载 ESM 用 `new Function('specifier','return import(specifier)')` 原生动态导入绕过(生产与测试均可用)。 15. **[必须] Angular 20 测试三坑**:①signal 版 NgModel 经 effect 异步初始化——首个稳定周期前派发的 input 事件全部无效(值被变更检测重置),必须先 `detectChanges → whenStable → detectChanges` 稳定一个周期再模拟输入;②expectOne 不幂等——同一 URL 第二次 expectOne 必失败,须保存第一次返回的 req 引用后 flush;③jest.mock 路径以文件真实位置为准(environments 常在 src/environments/ 而非 src/app/ 下),路径写错套件整体无法运行。 16. **[必须] 无头浏览器验收防挂起**:headless=new 下 `Page.setAutoAcceptDialogs` 对 confirm 弹窗不生效,JS 对话框会阻塞渲染进程导致 CDP 调用永久挂起——双保险:页面注入 `window.confirm = () => true` + 监听 `Page.javascriptDialogOpening` 事件主动 `handleJavaScriptDialog`;所有 CDP send 必须带超时,挂起即快速失败而非无限等待。 ## 建议规则 - [建议] 覆盖率报告:定期产出现有覆盖率报告,新模块测试先行(先写测试骨架再实现)。