| name | testspec-points |
| description | TestSpec 测试点(流程第 3 步)- 从需求分析中提炼「要测什么」的简短要点清单,产出 specs/testpoints.md。当用户要「写测试点」「提取测试要点」「列出要验证的内容」或执行 testspec-points / testspec points 时使用。也适用于用户说「这个功能要测哪些点」「帮我列测试清单」的场景。与测试用例区分:测试点只列验证目标(What),不写操作步骤(How)。产出供 testspec-generate 展开为完整测试用例。 |
testspec-points:测试点
IRON LAW: Test points describe what to verify, never how to execute it.
TestSpec Points Progress:
- [ ] Step 1: Locate current change directory ⚠️ REQUIRED
- [ ] Step 2: Load requirements-analysis.md or proposal.md ⚠️ REQUIRED
- [ ] Step 3: Consume upstream context and testlib signals
- [ ] Step 4: Generate specs/testpoints.md with naming dictionary
- [ ] Step 5: Validate naming contract and reflect
- [ ] Step 6: Seed context metadata and report next step
职责
从需求分析结论中提炼出简短的测试覆盖要点清单,作为 testspec-generate 的直接输入。
与 analysis 的关系:analysis 做深度拆解(等价类、边界值、状态迁移、风险点),points 是 analysis 的"精华版"——把分析结论转化为一条条简短的"要验什么"。如果已有 requirements-analysis.md,points 应该从中提炼而非重复分析;如果没有 analysis,points 按默认策略直接从 proposal.md 提炼。
核心定义
测试点(Test Point)
- 代表一个可独立验证的业务或功能验证目标
- 关注系统行为、业务规则或质量属性
- 不描述"如何测试",仅描述"验证什么"
测试点 ≠ 测试用例 ≠ 校验点
- 测试点:验证目标(What)
- 测试用例:操作步骤(How)
- 校验点:字段 / 状态 / 断言(Check)
测试点分类
每个测试点必须归属以下一种类型:
- 功能验证(Functional)
- 边界验证(Boundary)
- 异常验证(Exception)
- 集成验证(Integration)
- 非功能性验证(Non-Functional)
TP_ID 生成规则
格式:TP_<MODULE>_<FEATURE>_<SEQ>
- MODULE:2-5 位大写缩写(来自文档顶部「命名字典」)
- FEATURE:2-10 位大写缩写(来自文档顶部「命名字典」)
- 缩写不得临时发明;同一模块/功能点必须长期稳定复用同一缩写
- SEQ 范围按类别:
- 001–099:Functional
- 100–199:Boundary
- 200–299:Exception
- 300–399:Integration
- 400–499:Non-Functional
命名字典一致性
当 testspec/testlib/index.json 存在时,优先参考 testlib 中已有的 module_key/feature_key 缩写,避免同一模块在不同变更中使用不同缩写。仅对 testlib 中不存在的新模块/功能新建缩写。
TP_ID 是当前变更工作区内的测试点标识,SEQ 编号在每次变更内独立分配(从类别起始值开始),无需与 testlib 中的历史编号衔接。testlib 的更新管理基于仓库当前状态(ID + 标题语义匹配);index.json 中的 tp_ids 仅用于检索“该功能的用例覆盖过哪些测试点”,不参与 TP_ID 编号分配,也不要求跨变更唯一。
优先级规则
每个测试点必须标注优先级:
- P1:核心业务链路、权限、安全、资金、数据安全
- P2:常规业务功能、重要边界和异常
- P3:低频功能、边缘场景、体验类验证
回归套件分层
每个测试点可选标注回归套件层级,用于指导后续回归测试的选取范围。未标注时默认 Full。
- Smoke:系统基本可用性验证。失败意味着系统不可部署或核心业务链路中断。通常是 P1 中最关键的子集——最短业务闭环上的关键步骤。数量控制在总测试点的 10-20%。
- Full:完整回归覆盖。包括所有功能验证、边界验证和重要异常验证。常规版本发布前执行。
- Targeted:定向回归。仅在特定模块变更时执行的测试点,通常关联明确的变更影响范围(如某接口改动只影响下游 2 个功能)。
标注依据
Agent 根据以下信号自主判断层级,不套用固定比例:
- Smoke 信号:位于核心业务主线、失败会阻塞大部分功能、P1 且属于功能验证类型
- Targeted 信号:仅在特定模块变更时有回归价值、与其他模块耦合度低、关联需求范围明确且狭窄
- 其余归 Full:既不够关键到 Smoke,也不够隔离到 Targeted
粒度控制
- 一个测试点只验证一个业务意图
- 不以字段为单位拆分测试点
- 不以接口参数为单位拆分测试点
- 出现"且 / 并且 / 同时"时,评估是否拆分为多个测试点
- 测试点应长期稳定,不随实现细节变化
命名契约(points ↔ generate,必须遵守)
详见 ../_testspec-shared/references/naming-contract.md。生成 testpoints.md 后必须按其中的自检清单逐项验证。
禁止事项(严格)
- 不包含操作步骤(点击、输入、跳转等)
- 不包含具体测试数据
- 不包含接口字段名或表结构
- 不描述实现方式(Redis、MQ、数据库等)
- 不生成测试用例形式内容
反模式识别(Agent 自检参照)
生成 testpoints.md 后,对照以下反模式自查。发现符合的情况时自动修正。
| 反模式 | 表现 | 正确做法 |
|---|
| 字段级拆分 | 把"用户名""密码""验证码"各拆一个测试点 | 合并为"登录表单验证"一个测试点,字段级差异在 generate 阶段用等价类覆盖 |
| 等价类误认为测试点 | "密码长度 8-20"拆成"7位""8位""20位""21位"四个测试点 | 只设一个"密码长度边界验证"测试点,具体边界值在 generate 阶段展开 |
| 测试步骤泄漏 | 测试点描述中出现"点击""输入""选择"等操作动词 | 测试点只描述验证目标(What),不描述操作方法(How) |
| 模块失衡 | 某模块只有 1-2 个测试点而其他模块 10+ 个 | 检查是否遗漏了该模块的异常/边界/集成类别 |
| 类别缺失 | 全部测试点都是 Functional,没有 Boundary/Exception | 每个核心模块至少覆盖 Functional + 1 个其他类别 |
| 伪测试点 | "验证功能正常""确认系统可用"等无具体验证意图的描述 | 验证要点必须指向具体的业务行为或质量属性 |
当前变更目录
参见 ../_testspec-shared/references/common.md 中的「当前变更目录定位规则」。
推理式策略选择
按 ../_testspec-shared/references/thinking-protocol.md 执行推理式决策。
上游上下文消费
- 读取
requirements-analysis.md(优先)或 proposal.md
- 检查上游产物末尾是否包含上下文元数据(
<!-- testspec-context ... -->)
- 若有元数据:
- 提取
risks_identified → 确保对应风险有高优先级测试点
- 提取
blocking_open_questions → 标注为"需确认"的测试点
- 提取
material_quality → 影响推理深度
- 提取
testlib_coverage(若有)→ 直接使用 analysis 的扫描结论
- 检查
stale_downstream_artifacts:若命中 testpoints.md 或当前输入产物,停止执行并提示先运行 next_skill 或 testspec-analysis rebaseline
- 检查
source_revision.version:若上游版本高于当前输入产物 context 中记录的版本(或输入产物缺少 source_revision),停止执行并提示上游已更新、需先重跑上游 skill
- 门禁终止时仅输出:受影响产物名、过期原因(一句话)、建议运行的 skill 名称。不输出分析或部分结果。
testlib 知识库检索
若上游 testlib_coverage 不存在或 scanned = false,points 自行扫描:
- 检查
testspec/testlib/index.json 是否存在
- 若存在,读取 index.json 并匹配当前变更涉及的模块关键词
- 从匹配的模块中提取:
- 已有 TP_ID 列表(
tp_ids 字段):该功能历史用例曾覆盖过的测试点,用于理解覆盖范围
- 已有功能覆盖:哪些功能点已有测试覆盖
- 关联功能(
related_features):可能需要回归的关联功能
- 检索结论影响测试点生成策略:
- 功能未变更,testlib 已有用例覆盖 → 可标注“testlib 已覆盖”,减少重复展开
- 功能有变更 → 正常生成新 TP(每次变更 SEQ 独立),并结合历史
tp_ids 判断哪些区域需要回归
- 全新功能 → 正常生成
- 关联功能 → 考虑是否需要补充集成/回归类测试点
可复用资产识别
工作流中不应只找问题和风险——发现"我们已经有什么"同样重要,能显著提升效率。
在 testlib 检索完成后、覆盖策略推理前,回答以下问题:
- 已有覆盖复用:testlib 中哪些已有用例可以直接复用或微调?
- 自动化友好区域:哪些模块的功能天然适合自动化(纯数据校验、API 调用、幂等操作)?
- 测试数据共享:哪些模块之间可以共享测试前置数据(同一用户、同一订单贯穿多个模块)?
- 快速收益点:哪些测试点投入最小但覆盖价值最大(如一条冒烟用例覆盖核心链路 80%)?
产出:在 testpoints.md 的「知识库复用摘要」之后增加「可复用资产」小节:
## 可复用资产
- testlib 可直接复用:<功能点列表及对应 testlib 路径>
- 自动化友好区域:<模块列表及原因>
- 可共享测试数据:<数据类型及适用模块>
- 快速收益点:<TP_ID 及收益说明>
下游影响:
- testlib 已覆盖的功能点标记为"复用优先",generate 阶段优先参考已有用例风格
- 快速收益点在覆盖策略中获得优先安排
覆盖策略推理
通过 4 个核心问题决定覆盖深度:
- "核心业务价值链是什么?" → 决定 P1 测试点集中在哪些模块
- "哪些区域风险最高?" → 上游标注的风险区域加深覆盖
- "验证粒度应该多细?" → 材料信息密度高则可细化,低则保持粗粒度
- "知识库中已有哪些覆盖?" → testlib 已覆盖的功能点可降低优先级或标记复用
执行步骤
- 确定当前变更目录。
- 读取上下文:
- 优先读
requirements-analysis.md(从中提炼)
- 若不存在,读
proposal.md(直接提炼)
- 生成 specs/testpoints.md:
写入策略(重要)
为确保大文件写入成功,按以下优先级执行:
- 首选方案:使用当前执行环境的标准文件编辑机制写入完整内容
- 兜底方案:如果一次性写入失败,分段写入同一文件并保持 Markdown 结构完整
- 验证写入:读回文件前 10 行和末尾上下文元数据,确认内容正确
提炼原则
- 按模块/功能点组织,并按类别分区(Functional / Boundary / Exception / Integration / Non-Functional)
- 每条测试点必须包含:TP_ID、测试点名称、验证要点、优先级(P1/P2/P3)、关联需求
- 确保覆盖 analysis 中识别的风险点和边界值
- 不确定项标注"需与产品确认",优先级设为 P3,不补充假设性业务规则
输出质量要求
- 测试点必须完整覆盖需求
- 测试点之间不得重复
- 每个测试点必须可独立验证
- 测试点应可直接用于后续测试用例设计
默认行为
- 未特别说明时,按"最小充分覆盖"原则生成测试点
- 不主动扩展需求之外的业务场景
- 不推断实现细节
产出结构
# 测试点:<被测对象>
## 概述
<一两句话说明本次测试覆盖范围与重点>
## 知识库复用摘要
> 仅当 testlib 中存在相关覆盖时输出。无 testlib 或无匹配时跳过此节。
| 模块 | 功能点 | testlib 历史覆盖 TP 数 | 本次策略 |
|------|--------|-------------------|----------|
| <模块> | <功能> | N | 复用 / 新增 / 替代 |
**说明**:以下 TP_ID 表示历史用例覆盖过的测试点,供判断复用/回归范围参考:
- TP_XXX_YYY_001(testlib 路径:<module>/<feature>.json)
## 可复用资产
> 仅当 testlib 扫描发现可复用项时输出。无 testlib 或无匹配时跳过此节。
- testlib 可直接复用:<功能点列表及对应 testlib 路径>
- 自动化友好区域:<模块列表及原因>
- 可共享测试数据:<数据类型及适用模块>
- 快速收益点:<TP_ID 及收益说明>
## 命名字典
### 模块字典
| 模块名称 | MODULE |
|---|---|
| <模块名称> | <2-5 位大写缩写> |
### 功能点字典
| 模块名称 | 功能点名称 | FEATURE |
|---|---|---|
| <模块名称> | <功能点名称> | <2-10 位大写缩写> |
### [模块名称]模块
#### [功能点名称]功能
##### 功能验证点 (Functional)
- TP_<MODULE>_<FEATURE>_001: <测试点名称(格式:{模块}_{功能点}_{验证意图})>
- 验证要点: <验证什么(What),不写步骤/数据>
- 优先级: P1/P2/P3
- 回归层级: Smoke/Full/Targeted(可选,默认 Full)
- 关联需求: <需求编号/段落>
##### 边界验证点 (Boundary)
##### 异常验证点 (Exception)
##### 集成验证点 (Integration)
##### 非功能性验证点 (Non-Functional)
- 告知用户:产出路径及下一步可执行 testspec-generate。
完整模板见 references/testpoints-template.md。
反思与迭代
按 ../_testspec-shared/references/reflection-protocol.md 执行产物反思。
产物首次生成后,执行反思循环:
- 覆盖均衡性:各模块的测试点数量是否均衡?是否有模块只有 1-2 个点而其他模块 10+?
- 粒度一致性:不同模块的测试点粒度是否一致?(同样复杂度的功能,测试点数量差异不应超过 3 倍)
- 验证要点质量:每个验证要点是否可独立验证?是否有"验证功能正常"这种模糊描述?
反思后修正产物,最多 2 轮迭代。告知用户迭代次数和修正摘要。
上下文播种
在 specs/testpoints.md 末尾,按 ../_testspec-shared/references/context-protocol.md 播种元数据:
<!-- testspec-context
{
"source_skill": "testspec-points",
"coverage_estimate": "<各类别覆盖情况>",
"risks_identified": ["<从上游继承或新发现的风险>"],
"regression_tiers": {
"smoke": ["<Smoke 层级的 TP_ID>"],
"full": ["<Full 层级的 TP_ID>"],
"targeted": ["<Targeted 层级的 TP_ID>"]
},
"testlib_reuse": {
"existing_tp_ids": ["<testlib 中已覆盖的 TP_ID>"],
"new_tp_ids": ["<本次新增的 TP_ID>"]
}
}
-->
产物
testspec/changes/<name>/specs/testpoints.md