💻

Test Plan Writer

👤 1++ 📦 v1.0.12 ⭐ 4.5 ⬇️ 255 下载
💻 开发编程 免费

📖 技能介绍


slug: test-plan-writer name: test-plan-writer version: "1.0.12" changelog: - "1.0.12: 扩充知识库查询范围,增加服务相关查询维度(测试策略、数据筛选、功能开关、预期差异、业务场景)" - "1.0.11: 修复changelog格式、恢复description字段" - "1.0.9: 更新test-plan-template.md测试执行方式说明,区分Jenkins MCP与本地执行,移除压测流水线" - "1.0.8: 同步qa-integration-pipeline取消压测,required_phases更新为[1,2,3,4,5,6],Phase 6改为汇总报告" - "1.0.7: 明确sourceFiles为source_files.txt索引文件路径,更新检查清单A操作步骤" - "1.0.6: 对照组白名单支持独立driver_id,完善experiment_config说明" - "1.0.4: 修正changelog、补充experiment_config与分组预期差异" - "1.0.3: 增加 experiment_config 实验/灰度配置字段、分组预期差异格式、required_phases 映射更新(Case 生成必须执行,压测暂不执行)" - "1.0.2: 优化字段存在性检查、Thrift/Proto区分搜索、字段来源约束、待确认标注规范、自检清单" - "1.0.0: 初始版本,支持标准 test_plan.md 生成" displayName: "Test Plan Writer" description: "基于 PRD 和代码变更分析,生成标准化测试方案(test_plan.md)。职责包括:设计测试场景、定义数据筛选条件、评估风险等级、决定所需流水线阶段。"


测试方案生成器

角色定位

本 Skill 是方案设计层,专注测试方案生成,不执行具体测试。

职责: 1. 分析 PRD 需求与代码变更范围 2. 设计可观测协议字段级别的测试场景 3. 定义数据筛选条件(供下游 search-data 使用) 4. 评估风险等级,决定 required_phases 5. 生成标准化 test_plan.md


输入参数

参数 必填 说明
feature 功能名,用于目录命名和方案标识
designDoc map-spec 设计文档路径(.claude/workflow/<slug>/design.md
sourceFiles map-spec 传入的 source_files.txt 文件路径(.claude/workflow/<slug>/source_files.txt)。内容为纯文本,每行一个变更文件路径。仅用于辅助了解改动范围,不用于需求分析

执行步骤

⚠️ 前置强制检查(阻塞项 vs 警告项)

在生成测试方案前,必须完成以下检查。检查项分为两类:

类型 含义 未通过处理
🔴 阻塞项 必须修复,禁止继续 返回对应步骤修正
🟡 警告项 允许标注后通过,但需在输出中显性标注 记录到自检清单

检查清单 A:代码 diff 分析(🟡 警告项)

检查项 操作 通过标准 未通过处理
读取 sourceFiles read_file <sourceFiles> 获取索引文件,解析每行得到代码文件路径列表 索引文件已读取且至少包含一个有效路径 标注 [警告: sourceFiles 为空],继续
读取代码文件 对解析出的每个路径执行 read_file <路径> 关键文件内容已读取 标注 [待确认: 需开发确认],继续
提取日志关键字 grep_code regex="LOG.*<函数名>" path="<代码文件路径>"(对列表中各文件分别搜索) 找到日志语句 标注 [待确认: 需开发确认],继续
提取 Apollo Key grep_code regex="GetConfig|apollo" path="<代码文件路径>"(对列表中各文件分别搜索) 找到配置读取 标注 [待确认: 需开发确认],继续
确认改动分支 grep_code regex="if.*event_type.*5" path="<代码文件路径>"(对列表中各文件分别搜索) 找到条件分支 标注 [警告: 未找到相关分支],继续

为什么不阻塞? sourceFiles 可能为空(map-spec 未传入),或代码变更未提交到 git。允许降级为"待确认"标注,但必须在输出中显性记录。


检查清单 B:字段存在性确认(🔴 阻塞项)

检查项 操作 通过标准 未通过处理
Thrift 搜索 grep_code regex="<字段名>" path="src/navi-guide/src/proto/thrift" 找到字段定义 阻塞:禁止虚构字段
Proto 搜索 grep_code regex="<字段名>" path="src/navi-guide/src/proto/protobuf" 找到字段定义 阻塞:禁止虚构字段
建立字段来源表 记录字段所属消息和行号 每个字段都有来源 阻塞:必须补充来源

为什么阻塞? 虚构协议字段会导致测试方案完全不可执行,下游 search-data 和 diff 都会失败。这是底线。


检查清单 C:预期结果量化检查(🔴 阻塞项)

检查项 检查内容 通过标准 未通过处理
数值量化 包含具体数值或范围 如"数量 >= 1"而非"有效" 阻塞:返回修正
字段结构 包含具体的字段名 如"forkPoint 非空" 阻塞:返回修正
识别方法 内部状态的识别规则 如"通过 multiRoadsForkPoints 非空识别" 阻塞:返回修正

禁止使用的模糊词:正常、有效、正确、成功、合理、优化、提升、改善、包含有效信息、解析成功

例外处理:若确实无法量化(如用户体验类优化),在 说明 中写明量化困难原因替代验证方式 → 降为 🟡 警告项,允许通过。


Step 1: 读取设计文档

  1. 读取 designDoc
  2. 读取 map-spec 生成的设计文档
  3. 提取:功能描述生效场景改动点约束条件涉及的协议字段

  4. 提取测试设计要素

  5. 从 designDoc 中直接提取测试所需信息,包括:
    • trigger_condition:生效场景、约束条件
    • expected_behavior:功能描述中的预期输出
    • affected_fields:涉及的协议字段

Step 2: 提取关键信息

designDoc(map-spec 设计文档)中提取: - 功能描述与生效场景 - 涉及的协议字段(如 ttsContentvoiceTypeeventType) - 触发条件(如 scene_type == F_FORK && distance <= 150m) - 功能开关控制: - 开关类型(灰度 / AB实验 / Apollo配置 / 无) - Apollo Key、默认值 - 若是灰度:白名单内容 - 若是 AB实验:实验组/对照组白名单、实验ID - 若是 Apollo配置:本地配置是否生效 - 约束条件(如"不影响普通十字路口") - 改动点(文件、函数、插入位置)

可查询信息源(AI 在生成方案时可主动查询):

信息源 查询方式 用途
知识库(LLM-Wiki) 调用 http://10.190.56.84:8080/search 语义检索与 feature / sourceFiles / 字段名 / 服务相关关键词 了解同类功能的历史测试方案、已知问题、协议字段含义、边界条件、服务部署配置、测试策略决策、数据筛选经验、diff 分析规则、回归测试经验
历史用例 检索 src/navi_guide_tools/case/ 下同类功能的测试用例 复用或参考历史场景的 trigger_condition、数据筛选条件
协议定义 读取 src/navi-guide/src/proto/ 下的 .thrift / .proto 文件 提取协议中实际存在的字段名、字段类型、嵌套结构,作为黑盒测试的唯一输入输出依据
Apollo 配置 检索相关配置项或白名单定义 确认开关类型、白名单内容、AB 实验分组规则
代码变更 读取 sourceFiles 中的具体代码 diff 确认改动点、新增字段、条件分支逻辑

designDoc 是主要信息来源,已包含足够的需求描述和变更范围。当 designDoc 信息不足以准确描述预期输入输出(如字段取值范围、协议格式、历史兼容性约束)时,必须主动查询上述信息源补充,确保测试方案准确。

黑盒测试约束:本 Skill 生成的测试方案用于黑盒测试,所有 trigger_condition(输入条件)和 expected_behavior(预期输出)中的字段必须是协议中实际存在的字段。禁止构造协议中不存在的字段或假设未定义的嵌套结构。若对字段存在性有疑问,必须查询协议定义文件确认

Step 2.5: 字段存在性确认(阻塞项)

在生成任何测试场景之前,必须完成以下确认:

1. 字段存在性确认顺序(知识库 → Proto 真相源)

采用两级确认机制,平衡效率与准确性:

Step 1: 查询 LLM-Wiki 知识库(快速索引)
    └─ 字段在检索结果中?→ 是 → 直接使用,跳过 proto 搜索
    └─ 字段不在检索结果中?→ 否 → 进入 Step 2

Step 2: 搜索 Proto 文件(唯一真相源)
    └─ 字段在 proto 中?→ 是 → 新字段,记录并标注 [新增字段: 待 LLM-Wiki 同步]
    └─ 字段不在 proto 中?→ 否 → 进入 Step 3

Step 3: 代码 diff 辅助校验
    └─ 在 diff 中找到?→ 是 → 可能是内部变量,禁止用于测试
    └─ 在 diff 中也找不到?→ 否 → 标注 [待确认: 需开发确认]

LLM-Wiki 知识库检索

服务地址:http://10.190.56.84:8080 Collection:navi-guide-qa-knowledge(需预先创建并上传知识库文档)

检索方式:

POST http://10.190.56.84:8080/search
Content-Type: application/json

{
  "collection": "navi-guide-qa-knowledge",
  "query": "<feature 关键词 或 字段名>",
  "limit": 5
}

检索时机: - Step 1 字段存在性确认时,用字段名作为 query 快速检索 - 设计测试场景前,用 feature 关键词检索历史测试方案和已知问题 - 遇到边界条件不确定时,检索相关规则和经验 - 确定测试策略时:检索同类功能的 required_phases 决策依据、风险等级评估标准 - 定义数据筛选条件时:检索历史筛选方案(diff / script / reuse)的选择依据和 filter_config 模板 - 配置功能开关时:检索历史 Apollo Key 命名规范、灰度开关配置模式、AB 实验分组规则 - 定义预期差异时:检索历史 diff 预期差异定义格式、unexpected_diff 判定规则 - 设计业务场景时:检索业务规则、播报逻辑、轮次定义、场景触发条件等业务知识(如"播报轮次"、"路口类型"、"距离阈值"等)

检索结果中的 headingtext 可用于拼接 RAG 上下文,辅助测试方案设计。 LLM-Wiki 检索结果不能作为字段存在性的最终依据,最终确认仍需搜索 proto 文件。

协议文件(唯一真相源)

导航服务采用 Thrift 定义接口 + Protobuf 定义响应数据结构,需区分搜索:

字段类型 协议文件 搜索目标
请求字段(如 event_typeroute_type .thrift 文件 navi_guide_service.thrift 中的 NaviGuideRequest
响应字段(如 eventTypeforkPoint .proto 文件 RouteGuidanceInfoRouteGuidanceInfos 等消息

唯一搜索范围src/navi-guide/src/proto/

该目录下包含所有 Thrift 接口定义和 Protobuf 数据结构定义,不局限于 navi_guide_service.thriftnavi_guide_service_apply.proto

  • Thriftsrc/navi-guide/src/proto/thrift/*.thrift(13 个文件,含接口、请求/响应结构体)
  • Protosrc/navi-guide/src/proto/protobuf/*.proto(8 个文件,含响应数据结构、路线特征、放大图等)

其他路径(如 src/ng_diff_new/src/navi_guide_tools/ 下的 proto)不得作为字段存在性确认的依据

搜索策略: - 先用 grep_codesrc/navi-guide/src/proto/全局搜索字段名 - 若命中,读取具体文件确认字段所属消息和类型 - 若未命中,再用 search_file 扫描项目内其他 .thrift / .proto 作为兜底

2. 区分请求消息与响应消息

导航服务的协议结构特点: - 响应消息:通常为 RouteGuidanceInfo(单路径诱导信息)或 RouteGuidanceInfos(多路径诱导信息),包含 forkPointmultiRoadsForkPointseventTypettsContent 等字段 - 请求字段:请求参数(如 event_type)通常不在单独的 "Request" 消息中定义,而是通过以下方式确认: - 响应中 eventType 字段的注释为"请求时的event_type",说明它是从请求透传的参数 - 查阅 designDoc 中的请求参数说明 - 查阅历史用例中的请求构造代码

3. 搜索字段的具体操作

对候选字段执行以下验证,根据字段类型选择搜索目标

A. 请求字段(trigger_condition 中使用)→ 搜索 Thrift:

# 操作 1:在 thrift 目录下全局搜索字段名(精确匹配,区分大小写)
grep_code regex="字段名\s*:" path="src/navi-guide/src/proto/thrift"

# 操作 2:查看命中的文件,确认字段所属结构体
grep_code regex="struct\s+\w+\s*\{" path="<命中文件>" -A 100

B. 响应字段(expected_behavior / affected_fields 中使用)→ 搜索 Proto:

# 操作 1:在 proto 目录下全局搜索字段名(精确匹配,区分大小写)
grep_code regex="字段名\s*=" path="src/navi-guide/src/proto/protobuf"

# 操作 2:查看命中的文件,确认字段所属消息
grep_code regex="message\s+\w+\s*\{" path="<命中文件>" -A 200

# 操作 3:若无精确匹配,尝试模糊搜索
grep_code regex="字段名" path="src/navi-guide/src/proto/protobuf" -i

4. 建立字段来源表

每确认一个字段,记录到来源表:

字段名 来源(请求/响应) proto 中的消息 确认方式
eventType 响应(请求透传) RouteGuidanceInfo 精确匹配
multiRoadsForkPoints 响应 RouteGuidanceInfo 精确匹配

5. 代码 diff 辅助校验(解决字段名/关键字精确性)

此步骤利用代码变更内容辅助校验 designDoc 中提到的字段名、日志关键字、Apollo Key 是否与代码实现一致。不是需求融合,仅为命名精确性校验。

当 designDoc 中提到的以下信息需要精确确认时,读取代码 diff 辅助验证:

获取 diff 的方式(按优先级): 1. sourceFiles 参数中的变更文件列表 → 直接读取这些文件的关键代码段 2. 执行 git diff HEAD → 获取完整代码变更 3. 检查 workflowDir/diff-report.md → map-spec code-review 阶段已生成的 diff 报告

diff 辅助校验的应用场景

场景 操作 示例
designDoc 写 event_type,不确定 proto 中是 event_type 还是 eventType 在 diff 中搜索 event_typeeventType,看代码中实际使用的字段名 diff 中出现 eventType = request->event_type → 确认 proto 中是 eventType
designDoc 提到"日志打印 SetmultiRoadsForkPoints" 在 diff 中搜索 LOGprintf 语句,确认日志关键字 exact match diff 中出现 LOG(INFO) << "SetmultiRoadsForkPoints event_type=" → 确认关键字
designDoc 提到"灰度开关 fix_eventtype5" 在 diff 中搜索 apolloGetConfig,确认 Apollo Key 完整名称 diff 中出现 GetConfig("fix_eventtype5_parseforkpoint_gray_switch") → 确认 Key
designDoc 提到新增字段 fork_points 在 diff 中搜索 fork_points,若代码中只有 forkPointmultiRoadsForkPoints → 禁止虚构 fork_points

校验规则: - 若 designDoc 中的字段名/关键字与 diff 中的代码实现不一致,以代码实现为准 - 若 designDoc 中未提及但 diff 中发现新增字段/开关,在测试方案中标注为新增,并纳入字段来源表 - 若 diff 中也找不到对应字段,标注 [待确认: 需开发确认]

6. 字段不在现有来源表中的处理(新字段发现流程)

若搜索到的字段不在当前字段来源表中,说明可能是新引入的字段,执行:

  1. 确认是否为本次需求新增字段
  2. 结合 sourceFiles 和 diff 内容,确认该字段是否在本次变更中新增
  3. 若是新增字段 → 进入新字段确认流程
  4. 若是已有字段但来源表遗漏 → 补充到来源表

  5. 新字段确认流程Step A: 在 .proto 中定位字段所属消息(请求/响应) Step B: 确认字段类型(optional/required/repeated) Step C: 记录到字段来源表 Step D: 同步到 LLM-Wiki(见下方「新字段知识库同步」)

新字段知识库同步

当 Step 2 发现新字段时,直接通过 /index 同步到 LLM-Wiki:

POST http://10.190.56.84:8080/index
Content-Type: application/json

{
  "collection": "navi-guide-qa-knowledge",
  "docs": [
    {
      "id": "new-field-<feature>-<field_name>",
      "text": "字段: <field_name>\n类型: <type>\n所属消息: <Message>\n来源: <proto/thrift>\n说明: <简要说明>\n引入功能: <feature>"
    }
  ]
}

如批量发现多个新字段,合并为一个 docs 数组一次性 /index 注入。

  1. 临时处理:若来不及同步 LLM-Wiki,在字段来源表中标注 [新增字段: 待 LLM-Wiki 同步],但不影响测试方案生成

7. 标记不确定项:若 PRD 或 designDoc 中提到的概念无法映射到协议字段(如"版本切换"、"已走过的 link"),禁止直接虚构字段名,应: - 优先寻找协议中可间接表征该状态的字段 - 若找不到,在 trigger_condition 中使用最相关的真实字段(如 eventType == 5),并在说明中备注"版本切换状态通过响应差异反推" - 绝不能使用 C++ 内部变量名(如 route_has_version_switchhas_traveled_links)作为测试依据

8. 字段命名规范:严格使用 proto 文件中的字段名(区分大小写,如 eventType 而非 event_type

Step 3: 设计测试场景

📋 场景细分方法论

规则 1:触发条件相同的场景处理

当多个场景的 trigger_condition 完全相同(如都是 event_type == 5),必须采用以下方式之一

方式 A:合并场景(统计方式)(推荐)

### S001: event_type=5 场景(合并)

- **触发条件**: `event_type == 5`
- **预期分布**:
  - 版本切换场景(约 30%):`multiRoadsForkPoints` 有差异(CHANGED)
  - 无版本切换场景(约 70%):`multiRoadsForkPoints` 无差异(UNCHANGED)
- **识别方法**: 通过响应中 `multiRoadsForkPoints` 非空识别版本切换

方式 B:区分场景(明确识别方法)

### S001: event_type=5 且发生版本切换

- **触发条件**: `event_type == 5` **且满足以下之一**:
  - 响应中 `map_version` 与请求不一致
  - 响应中 `multiRoadsForkPoints` 非空(新逻辑生效后)
- **预期行为**: `multiRoadsForkPoints` 包含分歧点(数量 >= 1)

### S002: event_type=5 且无版本切换

- **触发条件**: `event_type == 5` **且**:
  - 响应中 `map_version` 与请求一致
- **预期行为**: `multiRoadsForkPoints` 与基线一致(UNCHANGED)

强制要求:若采用方式 B,必须给出明确的识别字段或方法,禁止仅标注"通过响应差异反推"而不说明具体方法。

规则 2:灰度开关场景完整覆盖

若需求提到灰度开关,必须包含以下场景:

场景 触发条件 预期差异 优先级
灰度关闭 event_type == 5(灰度开关关闭) UNCHANGED(与基线一致) P0
灰度开启-生效 event_type == 5(灰度开关开启,命中白名单) CHANGED(新逻辑生效) P0
灰度开启-未生效 event_type == 5(灰度开关开启,未命中白名单) UNCHANGED(走老逻辑) P0

规则 3:边界场景系统设计

必须覆盖的边界维度(根据业务逻辑选择至少 2 个维度,每个维度至少 2 个边界点):

维度 边界点 示例场景
时间/进度边界 刚触发、触发后一段时间、长期 刚版本切换、切换后 10km、切换后到达终点
空间边界 起点、中途、终点 起点 0km、中途 50%、终点前 100m
数量边界 0、1、多个 无分歧点、1 个分歧点、多个分歧点
状态边界 正常、异常、极限 正常版本切换、切换失败、多次切换

基于协议中实际存在的可观测字段设计测试场景,每个场景必须包含:

字段 说明 字段来源限制
scenario_id 唯一标识,如 S001 -
scenario_name 场景名称,简明描述测试意图 -
trigger_condition 触发条件(协议字段 + 阈值) 只能使用请求协议中的字段
expected_behavior 预期行为(具体字段值变化) 只能使用响应协议中的字段
affected_fields 受影响的可观测字段列表 只能使用响应协议中的字段
test_type diff / functional / boundary -
验证方式 协议字段 / 日志 / 协议+日志 若选日志协议+日志,日志关键字必须来自源码确认
priority P0 / P1 / P2 -

字段使用规则: - trigger_condition 中的字段必须是请求消息(Request)中实际存在的字段 - expected_behavioraffected_fields 中的字段必须是响应消息(Response)中实际存在的字段 - 禁止将 C++ 内部变量、临时计算量、未序列化的内存对象作为测试依据 - 若需求描述中的概念无法直接映射到协议字段,应使用最接近的真实字段,并在场景说明中解释映射关系

示例场景

### S001: F 路口提前播报
- **触发条件**: `scene_type == F_FORK && distance_to_fork <= 150m`
- **预期行为**: `ttsContent` 包含 "前方路口",提前 50m 播报
- **受影响字段**: `ttsContent`, `voiceType`
- **测试类型**: diff
- **优先级**: P0

Step 4: 定义数据筛选条件

为每个 diff 类型场景定义数据筛选条件:

条件维度 示例
scene_type F_FORK, T_JUNCTION
distance_range 100m ~ 200m
version >= 490
city_list 北京、上海、深圳
time_range 高峰时段覆盖

筛选条件字段限制: - 筛选条件只能使用请求协议中实际存在的字段 - 禁止用响应字段、C++ 内部变量或 AI 推导的抽象概念作为筛选维度 - 若需求涉及无法直接筛选的内部状态(如"版本切换"、"已走过的 link"),应: 1. 先用请求中可筛选的字段缩小范围(如 eventType == 5) 2. 再通过 diff 输出的响应差异来识别目标场景 3. 在 说明 列中标注"内部状态通过响应差异反推,非直接筛选"

生成 data_filter_conditions 字段,供 search-data-script 使用。

Step 5: 评估风险等级、测试策略与 required_phases

根据以下因素评估:

因素 高风险表现
改动范围 核心算法、多模块联动
影响面 全量用户、全场景
字段类型 语音播报、安全相关事件
历史稳定性 同类改动曾引发线上问题

风险等级与 required_phases 映射

风险等级 说明 required_phases
low 纯配置/文案变更,影响面极小 [1, 2, 3, 4]
medium 单一场景优化,影响面可控 [1, 2, 3, 4, 5, 6]
high 核心算法变更,多场景联动 [1, 2, 3, 4, 5, 6]

Phase 6(汇总报告)为必须执行阶段,用于汇总各 Phase 产物生成最终报告。

测试策略建议(写入 test_plan.md "测试策略"章节):

变更类型 Diff 功能 Case 回归 说明
纯配置/文案调整 必须 Case 生成验证配置生效
新功能/新场景 必须
算法优化 必须 diff 覆盖核心差异,Case 验证边界
逻辑修复/Bugfix 必须 Case 验证边界场景
接口变更 必须

功能 Case 为必须执行,用于验证边界场景和补充 diff 无法覆盖的功能点。压测暂不执行。

逻辑修复特殊说明:若修复的是特定场景下的异常处理逻辑(如本例的 event-type=5 版本切换),功能 Case 用于验证边界场景(部分走过、全走过),压测通常不需要。需在"判断依据"中明确说明为何选择该策略。

AB 实验特殊策略: - Diff 需跑两组:实验组(基线 vs 实验组)+ 对照组(基线 vs 对照组) - 实验组预期:有差异(符合 test_plan 预期) - 对照组预期:无差异(对照组应与基线一致) - 对照组白名单:对照组可能使用独立白名单(driver_id 非空),也可能与非白名单共用默认逻辑(driver_id=""),视实验设计而定 - 若对照组出现差异 → 实验分流逻辑有问题,需标记为 bug

Step 6: 生成 test_plan.md

输出路径:<CASE_DIR>/<feature>/test_plan.md

test-plan-template-v2.md 模板格式生成,确保包含以下必填字段: - feature:功能名 - 测试执行方式:列出 Jenkins MCP 调度的流水线(diff 流水线 / 回归流水线 / 压测流水线),标注是否使用 - test_scenarios:测试场景列表(每个场景含 scenario_id / trigger_condition / expected_behavior / affected_fields / test_type / 验证方式 / priority) - 验证方式协议字段(仅 diff 验证) / 日志(仅日志验证) / 协议+日志(两者结合) - data_filter_conditions:数据筛选条件(供 search-data 使用) - 功能开关控制:开关类型、白名单、实验组等信息 - 测试策略:Diff / 功能 Case / 回归 / 压测 的是否需要执行 - experiment_config:实验/灰度配置(决定 diff 执行次数和分组) json { "type": "ab_test", "groups": [ {"name": "control", "driver_id": "202606101119", "desc": "对照组(白名单A)"}, {"name": "treatment", "driver_id": "580548822047701", "desc": "实验组(白名单B)"} ] } - typenone(无实验)/ ab_test / grayscale - groups:diff 分组列表,每组含 namedriver_iddesc - driver_id:该组的白名单 ID。空字符串表示非白名单(走默认逻辑),非空字符串表示使用该白名单 - 对照组可能有自己的白名单(如对照组白名单A),也可能不设白名单(空字符串,与非白名单共用默认逻辑) - 由功能开关控制信息自动推导:若开关类型为 AB实验/灰度,则 type 对应设置,groups 按对照组/实验组或白名单/非白名单拆分 - diff_config:Diff 执行配置与预期结果(输入不可预期,但输出必须可预期) - 对比配置:基线/目标服务地址(对比字段、忽略字段、请求数据来源等由 ng_diff_new 内部实现决定,测试方案仅指定 host) - 预期差异结果(Expected Diff):每个场景下哪些字段、基线值→目标值、变化方向(CHANGED/ADDED/REMOVED/UNCHANGED)。注意:diff 输入为线上真实流量,无法预先控制哪些请求会被打到,上表定义的是"如果某个请求的响应中该字段出现差异,则差异应符合上述定义" - 分组预期差异:按 experiment_config.groups 中的 name 分组定义预期差异,格式如下: markdown | 分组 | 场景ID | 字段 | 基线值 | 目标值 | 变化方向 | |------|--------|------|--------|--------|----------| | treatment | S001 | ttsContent | - | 包含"前方路口" | CHANGED | | treatment | S001 | multiRoadsForkPoints | 空 | 数量>=1 | ADDED | | control | S001 | ttsContent | - | - | UNCHANGED | | control | S001 | multiRoadsForkPoints | - | - | UNCHANGED | - 实验组/白名单组:按正常场景预期填写(CHANGED / ADDED / REMOVED) - 对照组/非白名单组全部为 UNCHANGED,与基线一致。若对照组出现任何差异 → 实验分流逻辑有 bug(对照组无论是否有独立白名单,都应与基线一致) - 非预期差异判定规则:哪些情况属于 unexpected_diff,供 Phase 2 diff-executor 使用 - 日志验证(如适用):哪些场景需结合日志验证、日志关键字/指标、预期结果 - required_phases:需要执行的 Phase 列表 - risk_level:风险等级(low/medium/high)

生成过程中的强制校验: 每生成一个场景,立即执行: 1. 字段来源校验trigger_condition 中的字段是否都在请求 proto 中?expected_behavior / affected_fields 中的字段是否都在响应 proto 中? 2. 字段命名校验:字段名是否与 proto 中完全一致(区分大小写)? 3. 任一校验失败,禁止继续生成,必须先修正字段

待确认项标注规范: 以下信息若无法从现有文档/代码中直接确认,必须标注 [待确认: 需开发确认],禁止虚构:

信息项 示例 标注方式
Apollo Key fix_eventtype5_parseforkpoint_gray_switch [待确认: 需开发确认] Apollo Key
日志关键字 SetmultiRoadsForkPoints event_type=5 [待确认: 需开发确认] 日志关键字
白名单内容 具体城市/用户群体 [待确认: 需开发确认] 白名单
字段存在性 不确定某字段是否在协议中 必须先查询 proto 确认,不能标注待确认

日志关键字获取方式:优先读取 sourceFiles 中的源码,搜索 LOG / WARN / ERROR / INFO 等日志输出语句,提取实际日志格式。若源码不可读或未找到相关日志,则标注 [待确认: 需开发确认]

模板文件位置:testing/test-plan-writer/test-plan-template.md

Step 7: 自检与输出

生成完成后,AI 自检以下项。以下检查项为阻塞项,任一项未通过必须修正后方可输出:

  • [ ] feature 字段与目录名一致
  • [ ] test_scenarios 非空,每个场景有完整字段
  • [ ] data_filter_conditionstest_scenarios 一一对应
  • [ ] data_filter_conditions 中的字段均为请求协议中实际存在的字段(无 C++ 内部变量)
  • [ ] 功能开关控制 完整(开关类型、白名单/实验组信息)
  • [ ] 测试策略 已根据变更类型自动判断(Diff / 功能 Case / 回归 / 压测),且判断依据明确
  • [ ] required_phases 与测试策略一致
  • [ ] risk_level 评估有依据
  • [ ] Diff 预期结果完整性diff_config 中每个 diff 类型场景都有对应的预期差异定义(含场景ID、字段、基线值、目标值、变化方向)
  • [ ] AB 实验对照组预期:若为 AB 实验,对照组的预期差异明确为 UNCHANGED(与基线一致)
  • [ ] 代码 diff 分析(阻塞项):若 sourceFiles 非空或 git diff HEAD 可执行,已从 diff 中提取实际日志关键字和 Apollo Key;禁止在已执行 diff 分析的情况下仍标注 [待确认: 需开发确认]
  • [ ] 预期结果量化(阻塞项):每个 expected_behavior 包含具体数值、状态或范围;无"正常"、"有效"、"正确"等模糊描述;若无法量化,说明中已写明量化困难原因和替代验证方式
  • [ ] 内部状态识别(阻塞项):designDoc 中提到的内部状态(如"版本切换"、"已走过的 link")已通过识别方法或场景合并处理;trigger_condition 中无无法从请求字段推断的内部状态
  • [ ] 协议字段存在性(阻塞项)trigger_condition 中的字段均在请求协议中存在;expected_behavior / affected_fields 中的字段均在响应协议中存在;无虚构字段;字段名大小写与 proto 一致
  • [ ] 日志关键字来源:若使用了日志验证,日志关键字已标注 [待确认: 需开发确认] 或已读取源码/diff 确认
  • [ ] Apollo Key 来源:若提到了灰度开关/AB实验,Apollo Key 已标注 [待确认: 需开发确认] 或已从 diff 中提取实际值
  • [ ] 新字段知识库同步:若使用了本次需求新增的字段,已通过 /index 同步到 LLM-Wiki navi-guide-qa-knowledge(或已标注 [新增字段: 待 LLM-Wiki 同步]

自检失败处理流程: 1. 标记失败的检查项 2. 返回对应 Step 修正(字段问题 → Step 2.5/Step 3,日志问题 → 读取源码或标注待确认) 3. 重新执行自检,直至全部通过

执行日志(必须包含在输出中,便于审计):

## 执行日志

### 检查清单 A:代码 diff 分析
- [✅/❌/⚠️] 读取 sourceFiles:`ng_crossfinder_strategy.cpp`
- [✅/❌/⚠️] 搜索日志关键字:找到 `LOG(INFO) << "SetmultiRoadsForkPoints event_type="`
- [✅/❌/⚠️] 搜索 Apollo Key:找到 `GetConfig("fix_eventtype5_parseforkpoint_gray_switch")`
- [✅/❌/⚠️] 搜索分支逻辑:找到 `if (event_type == 5)`

### 检查清单 B:字段存在性确认
- [✅] Thrift 搜索 `event_type`:找到 `NaviGuideRequest` line 332
- [✅] Proto 搜索 `eventType`:找到 `RouteGuidanceInfo` line 1617
- [✅] Proto 搜索 `multiRoadsForkPoints`:找到 `RouteGuidanceInfo` line 1610
- [✅] 建立字段来源表:已完成(4 个字段全部确认)

### 检查清单 C:预期结果量化
- [✅] S001 expected_behavior:`multiRoadsForkPoints.size() >= 1`(已量化)
- [✅] S002 expected_behavior:`eventType == 5`(已量化)
- [⚠️] S003 expected_behavior:`与基线一致`(降级为警告,原因:回归场景无具体数值可量化)

### 场景细分检查
- [✅] 触发条件相同处理:S001-S005 的 trigger_condition 均为 `event_type == 5`,已合并为统计方式
- [✅] 灰度开关覆盖:已覆盖关闭/开启生效/开启未生效 3 个场景
- [✅] 边界维度:覆盖数量边界(0/1/多个)和空间边界(起点/中途/终点)

### 质量门禁
- [✅] 待确认项数量:2 项(白名单内容、日志关键字精确格式)
- [✅] 模糊描述检查:无模糊词
- [✅] 字段存在性:无虚构字段

作用:便于用户检查 AI 是否真的执行了关键步骤,便于事后审计和改进。

输出摘要(告知用户,无需确认):

测试方案已生成:

【功能概述】<简述>
【测试场景】共 X 个场景(P0: a个, P1: b个, P2: c个)
【功能开关】<开关类型> / <Apollo Key>
【测试策略】(已自动判断)
  - Diff 对比: 是/否
  - 功能 Case: **必须执行**
  - 回归测试: 是/否
【风险等级】<low/medium/high>
【执行阶段】required_phases = [...]

任一自检失败,重新生成并标注修正点。


输出校验

生成完成后,自检以下项:

  • [ ] feature 字段与目录名一致
  • [ ] test_scenarios 非空,每个场景有完整字段
  • [ ] data_filter_conditionstest_scenarios 一一对应
  • [ ] data_filter_conditions 中的筛选字段均为请求协议中实际存在的字段
  • [ ] required_phases 包含 Phase 1(自身)
  • [ ] risk_level 评估有依据(引用改动范围或影响面)
  • [ ] 筛选映射表 中每条预期差异都有场景对应
  • [ ] trigger_condition 字段均为请求协议字段,expected_behavior / affected_fields 字段均为响应协议字段
  • [ ] 无虚构字段,字段名大小写与 proto 一致
  • [ ] 日志关键字和 Apollo Key 已确认或已标注 [待确认: 需开发确认]

校验失败处理: 1. 标注具体失败项和原因 2. 返回对应 Step 修正 3. 重新校验直至全部通过


产出清单

产物 路径
测试方案 <CASE_DIR>/<feature>/test_plan.md

🤖 AI 评测

这个 Skill 质量很好,文档详细、逻辑清晰、使用方便。做得好的地方:步骤流程完整、检查清单详细、有现成的模板和示例;做了很多质量把关措施,能避免常见错误。不足之处:依赖内部服务地址、不方便在外部使用;有些细节说明分散在多处,查找不够方便。总体来说,这是一个专业度高、实用性强的 Skill。

📊 多维度评分

适应性4.3
规范性4.4
有效性4.7
可靠性4.4
可信度5

📁 包含文件 (3 个)

📄 SKILL.md 35.7 KB
📄 test-plan-demo.md 8.3 KB
📄 test-plan-template.md 10.5 KB

🔥 大家都在搜

wps 写作 pdf 苹果