dev-playbooks-cn 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +466 -0
- package/bin/devbooks.js +987 -0
- package/package.json +43 -0
- package/skills/Skills/344/275/277/347/224/250/350/257/264/346/230/216.md +446 -0
- package/skills/Skill/345/274/200/345/217/221/346/214/207/345/215/227.md +248 -0
- package/skills/_shared/context-detection-template.md +315 -0
- package/skills/_shared/mcp-enhancement-template.md +144 -0
- package/skills/_shared/references//351/200/232/347/224/250/345/256/210/351/227/250/345/215/217/350/256/256.md +114 -0
- package/skills/_template/config-discovery-template.md +126 -0
- package/skills/devbooks-brownfield-bootstrap/SKILL.md +167 -0
- package/skills/devbooks-brownfield-bootstrap/references//344/273/243/347/240/201/345/257/274/350/210/252/347/255/226/347/225/245.md +203 -0
- package/skills/devbooks-brownfield-bootstrap/references//345/255/230/351/207/217/351/241/271/347/233/256/345/210/235/345/247/213/345/214/226.md +96 -0
- package/skills/devbooks-brownfield-bootstrap/references//345/255/230/351/207/217/351/241/271/347/233/256/345/210/235/345/247/213/345/214/226/346/217/220/347/244/272/350/257/215.md +115 -0
- package/skills/devbooks-brownfield-bootstrap/references//346/234/257/350/257/255/350/241/250/346/250/241/346/235/277.md +42 -0
- package/skills/devbooks-brownfield-bootstrap/scripts/cod-update.sh +357 -0
- package/skills/devbooks-brownfield-bootstrap/templates/project-profile-template.md +172 -0
- package/skills/devbooks-c4-map/SKILL.md +151 -0
- package/skills/devbooks-c4-map/references/C4/346/236/266/346/236/204/345/234/260/345/233/276/346/217/220/347/244/272/350/257/215.md +33 -0
- package/skills/devbooks-c4-map/references//345/210/206/345/261/202/347/272/246/346/235/237/346/243/200/346/237/245/346/270/205/345/215/225.md +185 -0
- package/skills/devbooks-code-review/SKILL.md +175 -0
- package/skills/devbooks-code-review/references/PR/346/250/241/346/235/277/344/270/216/346/214/207/345/215/227.md +321 -0
- package/skills/devbooks-code-review/references//344/273/243/347/240/201/350/257/204/345/256/241/346/217/220/347/244/272/350/257/215.md +100 -0
- package/skills/devbooks-code-review/references//345/235/217/345/221/263/351/201/223/351/200/237/346/237/245/350/241/250.md +495 -0
- package/skills/devbooks-code-review/references//350/265/204/346/272/220/347/256/241/347/220/206/345/256/241/346/237/245/346/270/205/345/215/225.md +311 -0
- package/skills/devbooks-coder/SKILL.md +219 -0
- package/skills/devbooks-coder/references//344/273/243/347/240/201/345/256/236/347/216/260/346/217/220/347/244/272/350/257/215.md +70 -0
- package/skills/devbooks-coder/references//344/275/216/351/243/216/351/231/251/346/224/271/345/212/250/346/212/200/346/234/257.md +275 -0
- package/skills/devbooks-coder/references//346/227/245/345/277/227/350/247/204/350/214/203.md +329 -0
- package/skills/devbooks-coder/references//347/274/226/347/240/201/351/243/216/346/240/274/347/273/206/345/210/231.md +351 -0
- package/skills/devbooks-coder/references//351/224/231/350/257/257/347/240/201/350/247/204/350/214/203.md +463 -0
- package/skills/devbooks-delivery-workflow/SKILL.md +217 -0
- package/skills/devbooks-delivery-workflow/references//344/272/244/344/273/230/351/252/214/346/224/266/345/267/245/344/275/234/346/265/201.md +256 -0
- package/skills/devbooks-delivery-workflow/references//345/216/237/345/236/213-/347/224/237/344/272/247/345/217/214/350/275/250/346/250/241/345/274/217.md +168 -0
- package/skills/devbooks-delivery-workflow/references//345/217/230/346/233/264/351/252/214/350/257/201/344/270/216/350/277/275/346/272/257/346/250/241/346/235/277.md +133 -0
- package/skills/devbooks-delivery-workflow/scripts/ac-trace-check.sh +330 -0
- package/skills/devbooks-delivery-workflow/scripts/audit-scope.sh +262 -0
- package/skills/devbooks-delivery-workflow/scripts/change-check.sh +1040 -0
- package/skills/devbooks-delivery-workflow/scripts/change-codemod-scaffold.sh +135 -0
- package/skills/devbooks-delivery-workflow/scripts/change-evidence.sh +152 -0
- package/skills/devbooks-delivery-workflow/scripts/change-scaffold.sh +442 -0
- package/skills/devbooks-delivery-workflow/scripts/change-spec-delta-scaffold.sh +136 -0
- package/skills/devbooks-delivery-workflow/scripts/constitution-check.sh +237 -0
- package/skills/devbooks-delivery-workflow/scripts/env-match-check.sh +128 -0
- package/skills/devbooks-delivery-workflow/scripts/fitness-check.sh +387 -0
- package/skills/devbooks-delivery-workflow/scripts/guardrail-check.sh +519 -0
- package/skills/devbooks-delivery-workflow/scripts/handoff-check.sh +141 -0
- package/skills/devbooks-delivery-workflow/scripts/hygiene-check.sh +340 -0
- package/skills/devbooks-delivery-workflow/scripts/migrate-from-openspec.sh +385 -0
- package/skills/devbooks-delivery-workflow/scripts/migrate-to-v2-gates.sh +202 -0
- package/skills/devbooks-delivery-workflow/scripts/progress-dashboard.sh +319 -0
- package/skills/devbooks-delivery-workflow/scripts/prototype-promote.sh +341 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-preview.sh +203 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-promote.sh +118 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-rollback.sh +124 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-stage.sh +117 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-all.sh +78 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-npm-package.sh +123 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-openspec-free.sh +81 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-slash-commands.sh +146 -0
- package/skills/devbooks-delivery-workflow/templates/handoff.md +50 -0
- package/skills/devbooks-design-backport/SKILL.md +73 -0
- package/skills/devbooks-design-backport/references//345/233/236/345/206/231/350/256/276/350/256/241/346/226/207/346/241/243/346/217/220/347/244/272/350/257/215.md +196 -0
- package/skills/devbooks-design-doc/SKILL.md +121 -0
- package/skills/devbooks-design-doc/references//345/276/256/346/234/215/345/212/241/350/256/276/350/256/241/346/270/205/345/215/225.md +149 -0
- package/skills/devbooks-design-doc/references//350/256/276/350/256/241/346/226/207/346/241/243/346/217/220/347/244/272/350/257/215.md +189 -0
- package/skills/devbooks-design-doc/references//351/232/220/347/247/201/345/220/210/350/247/204/346/243/200/346/237/245/346/270/205/345/215/225.md +240 -0
- package/skills/devbooks-entropy-monitor/SKILL.md +188 -0
- package/skills/devbooks-entropy-monitor/references//347/206/265/345/272/246/351/207/217/346/226/271/346/263/225/350/256/272.md +223 -0
- package/skills/devbooks-entropy-monitor/scripts/entropy-measure.sh +449 -0
- package/skills/devbooks-entropy-monitor/scripts/entropy-report.sh +303 -0
- package/skills/devbooks-entropy-monitor/templates/thresholds.json +99 -0
- package/skills/devbooks-federation/SKILL.md +264 -0
- package/skills/devbooks-federation/scripts/federation-check.sh +144 -0
- package/skills/devbooks-federation/templates/federation.yaml +89 -0
- package/skills/devbooks-impact-analysis/SKILL.md +135 -0
- package/skills/devbooks-impact-analysis/references//345/275/261/345/223/215/345/210/206/346/236/220/346/217/220/347/244/272/350/257/215.md +82 -0
- package/skills/devbooks-impact-analysis/scripts/graph-cache.sh +214 -0
- package/skills/devbooks-implementation-plan/SKILL.md +83 -0
- package/skills/devbooks-implementation-plan/references//347/274/226/347/240/201/350/256/241/345/210/222/346/217/220/347/244/272/350/257/215.md +99 -0
- package/skills/devbooks-index-bootstrap/SKILL.md +240 -0
- package/skills/devbooks-proposal-author/SKILL.md +83 -0
- package/skills/devbooks-proposal-author/references//346/217/220/346/241/210/346/222/260/345/206/231/346/217/220/347/244/272/350/257/215.md +66 -0
- package/skills/devbooks-proposal-challenger/SKILL.md +86 -0
- package/skills/devbooks-proposal-challenger/references//344/274/246/347/220/206/344/270/216/345/220/210/350/247/204/346/243/200/346/237/245/346/270/205/345/215/225.md +176 -0
- package/skills/devbooks-proposal-challenger/references//346/217/220/346/241/210/350/264/250/347/226/221/346/217/220/347/244/272/350/257/215.md +57 -0
- package/skills/devbooks-proposal-debate-workflow/SKILL.md +78 -0
- package/skills/devbooks-proposal-debate-workflow/references//346/217/220/346/241/210/345/257/271/350/276/251/345/267/245/344/275/234/346/265/201.md +24 -0
- package/skills/devbooks-proposal-debate-workflow/references//346/217/220/346/241/210/345/257/271/350/276/251/346/250/241/346/235/277.md +35 -0
- package/skills/devbooks-proposal-debate-workflow/scripts/proposal-debate-check.sh +102 -0
- package/skills/devbooks-proposal-judge/SKILL.md +78 -0
- package/skills/devbooks-proposal-judge/references//346/217/220/346/241/210/350/243/201/345/206/263/346/217/220/347/244/272/350/257/215.md +37 -0
- package/skills/devbooks-router/SKILL.md +346 -0
- package/skills/devbooks-spec-contract/SKILL.md +191 -0
- package/skills/devbooks-spec-contract/references/API/350/256/276/350/256/241/346/214/207/345/215/227.md +349 -0
- package/skills/devbooks-spec-contract/references//345/245/221/347/272/246/344/270/216/346/225/260/346/215/256/345/256/232/344/271/211/346/217/220/347/244/272/350/257/215.md +85 -0
- package/skills/devbooks-spec-contract/references//350/247/204/346/240/274/345/217/230/346/233/264/346/217/220/347/244/272/350/257/215.md +63 -0
- package/skills/devbooks-spec-contract/references//351/232/220/345/274/217/345/217/230/346/233/264/346/243/200/346/265/213/346/217/220/347/244/272/350/257/215.md +183 -0
- package/skills/devbooks-spec-contract/scripts/implicit-change-detect.sh +378 -0
- package/skills/devbooks-spec-gardener/SKILL.md +72 -0
- package/skills/devbooks-spec-gardener/references//350/247/204/346/240/274/345/233/255/344/270/201/346/217/220/347/244/272/350/257/215.md +41 -0
- package/skills/devbooks-test-owner/SKILL.md +172 -0
- package/skills/devbooks-test-owner/references//345/217/230/346/233/264/351/252/214/350/257/201/344/270/216/350/277/275/346/272/257/346/250/241/346/235/277.md +228 -0
- package/skills/devbooks-test-owner/references//345/274/202/346/255/245/347/263/273/347/273/237/346/265/213/350/257/225/347/255/226/347/225/245.md +316 -0
- package/skills/devbooks-test-owner/references//346/265/213/350/257/225/344/273/243/347/240/201/346/217/220/347/244/272/350/257/215.md +208 -0
- package/skills/devbooks-test-owner/references//346/265/213/350/257/225/345/210/206/345/261/202/347/255/226/347/225/245.md +281 -0
- package/skills/devbooks-test-owner/references//346/265/213/350/257/225/351/251/261/345/212/250.md +394 -0
- package/skills/devbooks-test-owner/references//350/247/243/344/276/235/350/265/226/346/212/200/346/234/257/351/200/237/346/237/245/350/241/250.md +432 -0
- package/skills/devbooks-test-reviewer/SKILL.md +189 -0
- package/templates/.devbooks/config.yaml +88 -0
- package/templates/claude-commands/devbooks/apply.md +38 -0
- package/templates/claude-commands/devbooks/archive.md +33 -0
- package/templates/claude-commands/devbooks/backport.md +19 -0
- package/templates/claude-commands/devbooks/bootstrap.md +19 -0
- package/templates/claude-commands/devbooks/c4.md +19 -0
- package/templates/claude-commands/devbooks/challenger.md +19 -0
- package/templates/claude-commands/devbooks/code.md +19 -0
- package/templates/claude-commands/devbooks/debate.md +19 -0
- package/templates/claude-commands/devbooks/delivery.md +19 -0
- package/templates/claude-commands/devbooks/design.md +19 -0
- package/templates/claude-commands/devbooks/entropy.md +19 -0
- package/templates/claude-commands/devbooks/federation.md +19 -0
- package/templates/claude-commands/devbooks/gardener.md +19 -0
- package/templates/claude-commands/devbooks/impact.md +19 -0
- package/templates/claude-commands/devbooks/index.md +19 -0
- package/templates/claude-commands/devbooks/judge.md +19 -0
- package/templates/claude-commands/devbooks/plan.md +19 -0
- package/templates/claude-commands/devbooks/proposal.md +19 -0
- package/templates/claude-commands/devbooks/quick.md +42 -0
- package/templates/claude-commands/devbooks/review.md +19 -0
- package/templates/claude-commands/devbooks/router.md +19 -0
- package/templates/claude-commands/devbooks/spec.md +19 -0
- package/templates/claude-commands/devbooks/test-review.md +19 -0
- package/templates/claude-commands/devbooks/test.md +19 -0
- package/templates/dev-playbooks/README.md +458 -0
- package/templates/dev-playbooks/changes/.gitkeep +1 -0
- package/templates/dev-playbooks/constitution.md +116 -0
- package/templates/dev-playbooks/project.md +96 -0
- package/templates/dev-playbooks/scripts/.gitkeep +1 -0
- package/templates/dev-playbooks/specs/_meta/anti-patterns/.gitkeep +2 -0
- package/templates/dev-playbooks/specs/_meta/glossary.md +47 -0
- package/templates/dev-playbooks/specs/_meta/project-profile.md +79 -0
- package/templates/dev-playbooks/specs/architecture/fitness-rules.md +95 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# 测试代码提示词
|
|
2
|
+
|
|
3
|
+
> **角色设定**:你是测试驱动开发领域的**最强大脑**——融合了 Kent Beck(TDD 创始人)、Michael Feathers(遗留代码测试)、Gerard Meszaros(xUnit Patterns)的智慧。你的测试设计必须达到这些大师级专家的水准。
|
|
4
|
+
|
|
5
|
+
最高指示(优先级最高):
|
|
6
|
+
- 在执行本提示词前,先阅读 `_shared/references/通用守门协议.md` 并遵循其中所有协议。
|
|
7
|
+
|
|
8
|
+
你是"测试负责 AI"(Test Owner AI)。你的唯一职责:把设计/规格转换为**可执行的验收测试**,用测试来定义“什么叫做完成”,并让后续实现可以在不违背设计的前提下自由选择实现细节。
|
|
9
|
+
|
|
10
|
+
输入材料(由我提供):
|
|
11
|
+
- 设计/规格文档
|
|
12
|
+
- 测试驱动/验收方法论(参考:`references/测试驱动.md`)
|
|
13
|
+
|
|
14
|
+
产物落点(目录约定,协议无关):
|
|
15
|
+
- 测试计划与追溯文档推荐保存为:`<change-root>/<change-id>/verification.md`
|
|
16
|
+
- 测试代码变更仍落在仓库惯例目录(例如 `tests/`),但追溯矩阵与人工验收清单优先放在本次变更包内(verification.md),避免散落到对外 docs
|
|
17
|
+
|
|
18
|
+
同源隔离(必须遵守):
|
|
19
|
+
- **严禁**阅读/参考《编码计划(Implementation Plan)》来写测试(避免“按计划出题、按计划答题”的自证闭环)。
|
|
20
|
+
- 测试必须仅从设计/规格抽取验收标准与不变量;如果你发现设计缺口或歧义,只能提出“开放问题/假设”,不得用编码计划来填空。
|
|
21
|
+
- 你可以参考仓库现有测试框架与目录结构来落地测试,但不要让“现有实现细节”反向改写设计意图。
|
|
22
|
+
- **必须独立对话/独立实例**完成测试工作;不得与 Coder 共享上下文。测试改动必须由 Test Owner 完成,Coder 禁止修改 tests/。
|
|
23
|
+
- 确定性锚点优先:测试/静态检查/编译错误是唯一裁判;禁止用“AI 审查结论”替代锚点。
|
|
24
|
+
|
|
25
|
+
你的输出必须包含两部分(顺序固定):
|
|
26
|
+
|
|
27
|
+
========================
|
|
28
|
+
A) 测试计划指令表
|
|
29
|
+
========================
|
|
30
|
+
请创建/更新一份 测试计划指令表,并满足:
|
|
31
|
+
|
|
32
|
+
1) **计划区域必须放在文档最上方**,且包含:
|
|
33
|
+
- 主线计划区 (Main Plan Area)
|
|
34
|
+
- 临时计划区 (Temporary Plan Area)
|
|
35
|
+
- 【断点区】(Context Switch Breakpoint Area)
|
|
36
|
+
|
|
37
|
+
2) 计划区写法约束(硬约束):
|
|
38
|
+
- 计划区内容是“原文指令”,用于任务跟踪;你**不得**在计划区内写“完成/进行中”等状态标记,不得改写既有计划条目。
|
|
39
|
+
- 每个子任务必须含:目标(Why)、验收标准(Acceptance Criteria)、测试类型(unit/contract/integration/e2e)、不
|
|
40
|
+
可做事项(Non-goals)。
|
|
41
|
+
- 每个子任务都要有稳定 ID(如 `TP1.1`),便于引用与断点恢复。
|
|
42
|
+
|
|
43
|
+
3) 计划区之后,追加“计划细化区”,至少包含:
|
|
44
|
+
- Scope & Non-goals
|
|
45
|
+
- 测试金字塔与分层策略(unit/contract/integration/e2e 的边界)
|
|
46
|
+
- 测试矩阵(Requirement/Risk → Test IDs → 断言点 → 覆盖的验收标准)
|
|
47
|
+
- 测试数据与夹具策略(fixtures/golden data)
|
|
48
|
+
- 业务语言约束(去脚本化;不写 UI 操作与技术细节)
|
|
49
|
+
- 可复现性策略(时间/随机/网络/外部依赖)
|
|
50
|
+
- 风险与降级(哪些测试默认跳过、如何标记)
|
|
51
|
+
- 配置与依赖变更验证(Config Test / 版本一致性 / 依赖锁)
|
|
52
|
+
- 坏味道检测策略(静态检查/复杂度阈值/依赖规则;只使用现有工具)
|
|
53
|
+
|
|
54
|
+
========================
|
|
55
|
+
B) 测试代码实现(Repo 变更)
|
|
56
|
+
========================
|
|
57
|
+
在完成 A 后,开始在仓库中实现测试代码(只写测试,不写业务实现),要求:
|
|
58
|
+
|
|
59
|
+
【核心理念(必须遵守)】
|
|
60
|
+
1) **测试=可执行契约(Executable Spec)**:从“设计要求/验收标准/不变量”推导测试,而不是从“现有代码结构”推导测
|
|
61
|
+
试。
|
|
62
|
+
2) **行为优先、实现无关**:优先断言输出行为/数据契约/事件内容/不变量;避免断言私有函数调用次数、内部步骤顺序等实
|
|
63
|
+
现细节。
|
|
64
|
+
3) **确定性与可复现**:默认不联网、不依赖真实外部服务;冻结时间/随机种子;外部依赖用 fake/mock;输入数据固定可回
|
|
65
|
+
归。
|
|
66
|
+
4) **少而硬(风险驱动)**:优先覆盖最危险的失败模式(隔离、幂等/重放、质量闸门、错误级联阻断、契约漂移)。
|
|
67
|
+
|
|
68
|
+
**测试覆盖率分级要求**(辩论修订版):
|
|
69
|
+
> 来源:《重构》辩论修订版——从"一刀切80%"改为"分级要求"
|
|
70
|
+
|
|
71
|
+
| 代码类型 | 覆盖率要求 | 理由 |
|
|
72
|
+
|----------|------------|------|
|
|
73
|
+
| 核心业务逻辑 | >80% | 高风险,必须充分覆盖 |
|
|
74
|
+
| 公共模块/SDK | >60% | 中风险,被多处依赖 |
|
|
75
|
+
| 工具脚本/胶水代码 | >40% | 低风险,可适当放宽 |
|
|
76
|
+
| 待删除/废弃代码 | 不要求 | 打上 @Deprecated 即可 |
|
|
77
|
+
|
|
78
|
+
**重构前的测试要求**:
|
|
79
|
+
- 重构类变更(不改外部行为)必须先用 characterization tests 锁住现状
|
|
80
|
+
- 如涉及重构的模块测试覆盖率<对应分级要求,优先补充测试再重构
|
|
81
|
+
5) **分层清晰**:
|
|
82
|
+
- Unit:纯逻辑、无 IO
|
|
83
|
+
- Contract:schema/事件/数据契约、版本兼容、幂等键
|
|
84
|
+
- Integration:跨组件但可本地化(内存/容器可选),默认可跳过或标记
|
|
85
|
+
- E2E:只保留最小关键链路(UI/浏览器测试占比建议 ≤ 5%)
|
|
86
|
+
- Hermeticity:Small tests 禁止网络/磁盘 IO;Medium 仅允许 localhost;Large 才允许真实环境
|
|
87
|
+
6) **测试不替代实现**:测试里允许出现“复杂算法伪代码/结构化自然语言”用于说明断言逻辑,但不要在测试里实现一套业务
|
|
88
|
+
算法当作 oracle(除非是最小可验证的参考实现,并明确其范围)。
|
|
89
|
+
7) **反海勒姆(Anti-Hyrum)**:契约未承诺的行为不要断言;必要时在 fake/stub 中引入随机顺序/随机延迟,避免调用方依赖“未承诺细节”。
|
|
90
|
+
8) **结构锚点**:如 `<truth-root>/architecture/c4.md` 或设计中定义了边界/依赖方向,必须生成架构适配测试(fitness tests)。
|
|
91
|
+
9) **遗留安全网**:涉及重构/迁移/存量系统时,优先补快照测试(Snapshot/Golden Master)作为行为指纹。
|
|
92
|
+
10) **皮下测试优先**:能通过服务层/API 层验证的,不做 UI 测试;UI 仅用于最小连通性验证。
|
|
93
|
+
11) **胶水层隔离**:Spec 是只读文本;不要为自动化修改 spec 措辞。用 Glue Code/Fixtures/Builders 适配自动化。
|
|
94
|
+
12) **坏味道可检测则检测**:优先用现有 lint/静态规则/复杂度阈值/依赖规则做质量闸门;无法自动化则在 `verification.md` 中声明“人工/后续改进”。
|
|
95
|
+
|
|
96
|
+
【复杂逻辑的测试规范(减轻后续编码 AI 负担)】
|
|
97
|
+
当测试涉及复杂策略/算法(例如:去重、置信传播、三角验证、动态阈值、增量索引、调度策略),你必须在测试代码旁或测
|
|
98
|
+
试计划细化区新增 **Test Oracle Spec** 小节,包含:
|
|
99
|
+
- Inputs/Outputs
|
|
100
|
+
- 不变量(Invariants)与失败模式(Failure Modes)
|
|
101
|
+
- 核心流程伪代码(≤40 行、不可运行、抽象指令风格)
|
|
102
|
+
- 边界条件清单(至少 5 条)
|
|
103
|
+
- 对应测试用例 ID 映射(把每条边界条件映射到具体 test id)
|
|
104
|
+
|
|
105
|
+
【工程约束(硬约束)】
|
|
106
|
+
- 不新增全新测试框架;优先复用仓库既有框架与习惯用法。
|
|
107
|
+
- 不引入网络依赖;若必须写在线集成测试,必须:
|
|
108
|
+
- 明确标记(marker/tag)
|
|
109
|
+
- 默认跳过
|
|
110
|
+
- 提供本地 stub/fake 的替代路径
|
|
111
|
+
- 测试文件命名、目录结构、marker/tag、fixture 风格必须对齐仓库现状。
|
|
112
|
+
- 若为可测性必须调整生产代码:只允许做“最小可测性改动”(例如注入接口/依赖反转/时钟注入),并在计划细化区写明理由
|
|
113
|
+
与风险。
|
|
114
|
+
- 配置与依赖变更必须有“配置加载/默认值/版本一致性”测试或检查命令;不得仅做文本修改。
|
|
115
|
+
- 测试数据优先使用“原型/模板 + 小范围改动”,避免在测试里硬编码大段 JSON/SQL。
|
|
116
|
+
|
|
117
|
+
【交付与验收输出(必须)】
|
|
118
|
+
- 列出新增/修改的测试文件清单
|
|
119
|
+
- 列出如何运行测试的命令(按分层:unit/contract/integration/e2e)
|
|
120
|
+
- 给出“测试矩阵覆盖情况”摘要:哪些验收标准已被哪些测试 ID 覆盖
|
|
121
|
+
- 若存在暂无法可靠测试的点:必须解释原因,并给出降级测试方案(例如 contract test 替代 e2e)
|
|
122
|
+
- 同步更新追溯信息:把“验收标准 → Test IDs”映射更新到追溯矩阵(优先写入本次变更的 `verification.md`);对无法自动化的验收点,输出对应的 `MANUAL-*` 建议(同样优先放在 `verification.md`,必要时再同步到对外 docs)
|
|
123
|
+
- 输出“架构异味报告”:Setup 复杂度、Mock 数量、清理难度与建议的架构改进点
|
|
124
|
+
|
|
125
|
+
现在开始执行:
|
|
126
|
+
1) 先产出 测试计划指令表(按 A 的要求)
|
|
127
|
+
2) 再直接在仓库中实现测试代码(按 B 的要求)
|
|
128
|
+
3) 运行测试确认 **Red** 基线,并记录失败证据到 `<change-root>/<change-id>/evidence/`(或同等位置)
|
|
129
|
+
4) 最后输出一段简短摘要:测试覆盖了哪些验收标准、如何运行、哪些被标记为可选/跳过及原因
|
|
130
|
+
|
|
131
|
+
这是输入材料 和 产物目标路径:
|
|
132
|
+
|
|
133
|
+
========================
|
|
134
|
+
Z) 原型模式:表征测试(Characterization Tests)
|
|
135
|
+
========================
|
|
136
|
+
|
|
137
|
+
当检测到以下信号时,进入**原型模式**(Prototype Mode):
|
|
138
|
+
- 用户明确说"--prototype"或"原型模式"
|
|
139
|
+
- 存在 `<change-root>/<change-id>/prototype/` 目录
|
|
140
|
+
- 用户说"表征测试"或"characterization tests"
|
|
141
|
+
|
|
142
|
+
【表征测试 vs 验收测试】
|
|
143
|
+
|
|
144
|
+
| 类型 | 目的 | 来源 | 角色 |
|
|
145
|
+
|------|------|------|------|
|
|
146
|
+
| 验收测试 | 断言"应该是什么"(设计意图) | 设计/规格 | 生产轨道 |
|
|
147
|
+
| 表征测试 | 断言"实际是什么"(观察行为) | 运行结果 | 原型轨道 |
|
|
148
|
+
|
|
149
|
+
【原型模式产物落点】
|
|
150
|
+
|
|
151
|
+
- 表征测试代码:`<change-root>/<change-id>/prototype/characterization/`
|
|
152
|
+
- 测试命名:`test_characterize_<behavior>.py` 或 `*.characterization.test.ts`
|
|
153
|
+
- 不进入仓库 `tests/`,物理隔离于原型目录
|
|
154
|
+
|
|
155
|
+
【表征测试写法(必须遵守)】
|
|
156
|
+
|
|
157
|
+
1) **观察优先**:运行原型代码,记录实际输入/输出
|
|
158
|
+
2) **Golden Master 模式**:把实际输出固化为断言(快照式)
|
|
159
|
+
3) **标记隔离**:使用 `@characterization` 装饰器或 `describe.skip('characterization')` 标记,不进入 CI 主流程
|
|
160
|
+
4) **不需要 Red 基线**:原型模式下表征测试初始就是 Green(因为它断言的是"现状"而非"预期")
|
|
161
|
+
5) **用途声明**:当原型提升为生产时,表征测试作为行为基线参考,帮助识别"预期行为 vs 实现偏差"
|
|
162
|
+
|
|
163
|
+
【角色隔离(不变)】
|
|
164
|
+
|
|
165
|
+
- Test Owner 仍必须独立对话;不得与 Coder 共享上下文
|
|
166
|
+
- 表征测试由 Test Owner 产出,Coder 只读
|
|
167
|
+
- 原型模式下的角色隔离原则与生产轨道一致
|
|
168
|
+
|
|
169
|
+
【原型模式输出格式】
|
|
170
|
+
|
|
171
|
+
========================
|
|
172
|
+
A) 表征测试计划
|
|
173
|
+
========================
|
|
174
|
+
|
|
175
|
+
- 目标:记录原型代码的实际行为(而非验证设计意图)
|
|
176
|
+
- 范围:`<change-root>/<change-id>/prototype/src/` 中的代码
|
|
177
|
+
|
|
178
|
+
### 主线计划区
|
|
179
|
+
|
|
180
|
+
- [ ] CP1.1 <观察哪个行为>
|
|
181
|
+
- Input:
|
|
182
|
+
- Expected Output(观察到的):
|
|
183
|
+
- Golden File(如需快照):
|
|
184
|
+
|
|
185
|
+
========================
|
|
186
|
+
B) 表征测试实现
|
|
187
|
+
========================
|
|
188
|
+
|
|
189
|
+
```<language>
|
|
190
|
+
# @characterization - 原型行为快照,不进入 CI 主流程
|
|
191
|
+
# 当原型提升为生产时,此测试用于对比行为变化
|
|
192
|
+
|
|
193
|
+
def test_characterize_<behavior>():
|
|
194
|
+
# 记录观察到的实际行为
|
|
195
|
+
result = actual_prototype_call(...)
|
|
196
|
+
|
|
197
|
+
# Golden Master 断言:固化当前行为
|
|
198
|
+
assert result == <observed_output> # 来自运行观察
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
========================
|
|
202
|
+
C) 表征测试摘要
|
|
203
|
+
========================
|
|
204
|
+
|
|
205
|
+
- 覆盖的原型行为:
|
|
206
|
+
- Golden Files 路径:
|
|
207
|
+
- 运行命令:`pytest prototype/characterization/ -m characterization`
|
|
208
|
+
- 提升时注意:这些测试需要转换为验收测试(断言"应该是什么"而非"实际是什么")
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# 测试分层策略
|
|
2
|
+
|
|
3
|
+
借鉴 VS Code 的测试组织模式,本文档定义了测试分层的最佳实践。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1) 测试金字塔原则
|
|
8
|
+
|
|
9
|
+
### 理想比例
|
|
10
|
+
|
|
11
|
+
| 层级 | 比例 | 特点 | 执行频率 |
|
|
12
|
+
|------|------|------|----------|
|
|
13
|
+
| 单元测试 | 70% | 快速、隔离、聚焦 | 每次提交 |
|
|
14
|
+
| 集成测试 | 20% | 模块边界、真实依赖 | 每次 PR |
|
|
15
|
+
| E2E 测试 | 10% | 端到端、用户视角 | 每次合并 |
|
|
16
|
+
|
|
17
|
+
### 各层职责
|
|
18
|
+
|
|
19
|
+
**单元测试**:
|
|
20
|
+
- 测试单个函数/类的行为
|
|
21
|
+
- 完全隔离,无外部依赖
|
|
22
|
+
- 执行速度 < 5s/文件
|
|
23
|
+
- 覆盖所有边界条件
|
|
24
|
+
|
|
25
|
+
**集成测试**:
|
|
26
|
+
- 测试模块间交互
|
|
27
|
+
- 可使用测试数据库/缓存
|
|
28
|
+
- 执行速度 < 30s/文件
|
|
29
|
+
- 覆盖 API 契约
|
|
30
|
+
|
|
31
|
+
**E2E 测试**:
|
|
32
|
+
- 测试完整用户流程
|
|
33
|
+
- 使用真实环境
|
|
34
|
+
- 执行速度 < 60s/场景
|
|
35
|
+
- 只覆盖关键路径
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2) 测试命名约定
|
|
40
|
+
|
|
41
|
+
### 文件命名
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
src/
|
|
45
|
+
├── user/
|
|
46
|
+
│ ├── user.service.ts
|
|
47
|
+
│ └── test/
|
|
48
|
+
│ └── user.service.test.ts # 单元测试(紧邻源码)
|
|
49
|
+
|
|
50
|
+
tests/
|
|
51
|
+
├── unit/ # 备选:集中式单元测试
|
|
52
|
+
│ └── user.service.test.ts
|
|
53
|
+
├── integration/
|
|
54
|
+
│ └── user.api.integrationTest.ts # 集成测试
|
|
55
|
+
├── e2e/
|
|
56
|
+
│ └── user-flow.e2e.ts # E2E 测试
|
|
57
|
+
├── contract/
|
|
58
|
+
│ └── user.api.contract.ts # 契约测试
|
|
59
|
+
└── smoke/
|
|
60
|
+
└── health.smoke.ts # 烟雾测试
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 测试用例命名
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// Good: 描述行为和预期结果
|
|
67
|
+
describe('UserService', () => {
|
|
68
|
+
describe('createUser', () => {
|
|
69
|
+
it('should create a new user with valid data', () => {});
|
|
70
|
+
it('should throw ValidationError when email is invalid', () => {});
|
|
71
|
+
it('should return existing user when email already exists', () => {});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Bad: 模糊的描述
|
|
76
|
+
describe('UserService', () => {
|
|
77
|
+
it('test1', () => {});
|
|
78
|
+
it('works', () => {});
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3) 测试隔离策略
|
|
85
|
+
|
|
86
|
+
### 单元测试隔离
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// 使用 mock 隔离外部依赖
|
|
90
|
+
import { mock, MockProxy } from 'jest-mock-extended';
|
|
91
|
+
|
|
92
|
+
describe('UserService', () => {
|
|
93
|
+
let userRepo: MockProxy<UserRepository>;
|
|
94
|
+
let service: UserService;
|
|
95
|
+
|
|
96
|
+
beforeEach(() => {
|
|
97
|
+
userRepo = mock<UserRepository>();
|
|
98
|
+
service = new UserService(userRepo);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should call repository save', async () => {
|
|
102
|
+
userRepo.save.mockResolvedValue({ id: '1', name: 'test' });
|
|
103
|
+
await service.createUser({ name: 'test' });
|
|
104
|
+
expect(userRepo.save).toHaveBeenCalledWith({ name: 'test' });
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 集成测试隔离
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// 使用 beforeEach/afterEach 清理
|
|
113
|
+
describe('User API Integration', () => {
|
|
114
|
+
let testDb: TestDatabase;
|
|
115
|
+
|
|
116
|
+
beforeAll(async () => {
|
|
117
|
+
testDb = await TestDatabase.create();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
beforeEach(async () => {
|
|
121
|
+
await testDb.clean(); // 每个测试前清理
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
afterAll(async () => {
|
|
125
|
+
await testDb.destroy();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should create user via API', async () => {
|
|
129
|
+
const response = await request(app)
|
|
130
|
+
.post('/users')
|
|
131
|
+
.send({ name: 'test' });
|
|
132
|
+
expect(response.status).toBe(201);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### E2E 测试隔离
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// 使用独立的测试环境
|
|
141
|
+
describe('User Registration Flow', () => {
|
|
142
|
+
let browser: Browser;
|
|
143
|
+
let page: Page;
|
|
144
|
+
|
|
145
|
+
beforeAll(async () => {
|
|
146
|
+
browser = await chromium.launch();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
beforeEach(async () => {
|
|
150
|
+
page = await browser.newPage();
|
|
151
|
+
await seedTestData(); // 准备测试数据
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
afterEach(async () => {
|
|
155
|
+
await page.close();
|
|
156
|
+
await cleanupTestData(); // 清理测试数据
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
afterAll(async () => {
|
|
160
|
+
await browser.close();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 4) 测试稳定性保障
|
|
168
|
+
|
|
169
|
+
### 禁止提交的模式
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# pre-commit hook 检查
|
|
173
|
+
check_test_only() {
|
|
174
|
+
if rg -l '\.(only|skip)\(' tests/ src/**/test/; then
|
|
175
|
+
echo "error: found .only() or .skip() in tests" >&2
|
|
176
|
+
exit 1
|
|
177
|
+
fi
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Flaky 测试处理
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// 临时标记 flaky 测试(必须附带 issue 链接)
|
|
185
|
+
describe.skip('Flaky test - see #123', () => {
|
|
186
|
+
// TODO: Fix flaky test by 2024-01-15
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// 或使用重试(不推荐,应修复根因)
|
|
190
|
+
it('sometimes fails', async () => {
|
|
191
|
+
// jest-retries 或 mocha-retry
|
|
192
|
+
}, { retries: 2 });
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 超时设置
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// 合理的超时设置
|
|
199
|
+
jest.setTimeout(5000); // 单元测试默认 5s
|
|
200
|
+
|
|
201
|
+
describe('Integration Tests', () => {
|
|
202
|
+
beforeAll(() => {
|
|
203
|
+
jest.setTimeout(30000); // 集成测试 30s
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 5) 测试覆盖率策略
|
|
211
|
+
|
|
212
|
+
### 覆盖率目标
|
|
213
|
+
|
|
214
|
+
| 指标 | 最低要求 | 推荐目标 |
|
|
215
|
+
|------|----------|----------|
|
|
216
|
+
| 行覆盖率 | 70% | 80%+ |
|
|
217
|
+
| 分支覆盖率 | 60% | 70%+ |
|
|
218
|
+
| 函数覆盖率 | 80% | 90%+ |
|
|
219
|
+
|
|
220
|
+
### 覆盖率例外
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// 明确标记不需要覆盖的代码
|
|
224
|
+
/* istanbul ignore next */
|
|
225
|
+
function debugOnly() {
|
|
226
|
+
// 仅调试用,不需要测试
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* istanbul ignore if */
|
|
230
|
+
if (process.env.NODE_ENV === 'development') {
|
|
231
|
+
// 开发环境特定代码
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 6) 测试反脆弱策略(借鉴 VS Code Audit.md)
|
|
238
|
+
|
|
239
|
+
### 避免脆弱的选择器
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// Bad: 依赖 CSS 类名(容易因样式重构而失败)
|
|
243
|
+
await page.click('.btn-primary');
|
|
244
|
+
|
|
245
|
+
// Bad: 依赖文本内容(容易因国际化而失败)
|
|
246
|
+
await page.click('text=Submit');
|
|
247
|
+
|
|
248
|
+
// Good: 使用 data-testid
|
|
249
|
+
await page.click('[data-testid="submit-button"]');
|
|
250
|
+
|
|
251
|
+
// Good: 使用 role
|
|
252
|
+
await page.click('role=button[name="Submit"]');
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### 避免脆弱的断言
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Bad: 精确匹配(容易因格式变化而失败)
|
|
259
|
+
expect(result.createdAt).toBe('2024-01-01T00:00:00.000Z');
|
|
260
|
+
|
|
261
|
+
// Good: 类型断言
|
|
262
|
+
expect(result.createdAt).toBeInstanceOf(Date);
|
|
263
|
+
|
|
264
|
+
// Good: 模糊匹配
|
|
265
|
+
expect(result.message).toContain('success');
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 7) 测试审查检查清单
|
|
271
|
+
|
|
272
|
+
在 Code Review 时检查:
|
|
273
|
+
|
|
274
|
+
- [ ] 测试是否遵循命名约定?
|
|
275
|
+
- [ ] 单元测试是否完全隔离?
|
|
276
|
+
- [ ] 集成测试是否有清理逻辑?
|
|
277
|
+
- [ ] 是否有 `.only()` 或 `.skip()` 残留?
|
|
278
|
+
- [ ] 超时设置是否合理?
|
|
279
|
+
- [ ] 是否避免了脆弱的选择器?
|
|
280
|
+
- [ ] 新增代码是否有对应的测试?
|
|
281
|
+
- [ ] 测试是否覆盖了边界条件?
|