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)。內容為純文本,每行一個變更檔案路徑。僅用於輔助瞭解改動範圍,不用於需求分析 |
在生成測試方案前,必須完成以下檢查。檢查項分為兩類:
| 型別 | 含義 | 未通過處理 |
|---|---|---|
| 🔴 阻塞項 | 必須修復,禁止繼續 | 返回對應步驟修正 |
| 🟡 警告項 | 允許標註後通過,但需在輸出中顯性標註 | 記錄到自檢清單 |
| 檢查項 | 操作 | 通過標準 | 未通過處理 |
|---|---|---|---|
| 讀取 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。允許降級為"待確認"標註,但必須在輸出中顯性記錄。
| 檢查項 | 操作 | 通過標準 | 未通過處理 |
|---|---|---|---|
| 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 都會失敗。這是底線。
| 檢查項 | 檢查內容 | 通過標準 | 未通過處理 |
|---|---|---|---|
| 數值量化 | 包含具體數值或範圍 | 如"數量 >= 1"而非"有效" | 阻塞:返回修正 |
| 欄位結構 | 包含具體的欄位名 | 如"forkPoint 非空" |
阻塞:返回修正 |
| 識別方法 | 內部狀態的識別規則 | 如"通過 multiRoadsForkPoints 非空識別" |
阻塞:返回修正 |
禁止使用的模糊詞:正常、有效、正確、成功、合理、最佳化、提升、改善、包含有效資訊、解析成功
例外處理:若確實無法量化(如使用者體驗類最佳化),在 說明 中寫明量化困難原因和替代驗證方式 → 降為 🟡 警告項,允許通過。
designDoc提取:功能描述、生效場景、改動點、約束條件、涉及的協議欄位
提取測試設計要素
trigger_condition:生效場景、約束條件expected_behavior:功能描述中的預期輸出affected_fields:涉及的協議欄位從 designDoc(map-spec 設計文件)中提取:
- 功能描述與生效場景
- 涉及的協議欄位(如 ttsContent、voiceType、eventType)
- 觸發條件(如 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 判定規則
- 設計業務場景時:檢索業務規則、播報邏輯、輪次定義、場景觸發條件等業務知識(如"播報輪次"、"路口型別"、"距離閾值"等)
檢索結果中的
heading和text可用於拼接 RAG 上下文,輔助測試方案設計。 LLM-Wiki 檢索結果不能作為欄位存在性的最終依據,最終確認仍需搜尋 proto 檔案。
協議檔案(唯一真相源):
導航服務採用 Thrift 定義介面 + Protobuf 定義響應資料結構,需區分搜尋:
| 欄位型別 | 協議檔案 | 搜尋目標 |
|---|---|---|
請求欄位(如 event_type、route_type) |
.thrift 檔案 |
navi_guide_service.thrift 中的 NaviGuideRequest |
響應欄位(如 eventType、forkPoint) |
.proto 檔案 |
RouteGuidanceInfo、RouteGuidanceInfos 等訊息 |
唯一搜索範圍:src/navi-guide/src/proto/
該目錄下包含所有 Thrift 介面定義和 Protobuf 資料結構定義,不侷限於 navi_guide_service.thrift 或 navi_guide_service_apply.proto:
src/navi-guide/src/proto/thrift/*.thrift(13 個檔案,含介面、請求/響應結構體)src/navi-guide/src/proto/protobuf/*.proto(8 個檔案,含響應資料結構、路線特徵、放大圖等)其他路徑(如
src/ng_diff_new/、src/navi_guide_tools/下的 proto)不得作為欄位存在性確認的依據。
搜尋策略:
- 先用 grep_code 在 src/navi-guide/src/proto/ 下全域性搜尋欄位名
- 若命中,讀取具體檔案確認欄位所屬訊息和型別
- 若未命中,再用 search_file 掃描專案內其他 .thrift / .proto 作為兜底
2. 區分請求訊息與響應訊息
導航服務的協議結構特點:
- 響應訊息:通常為 RouteGuidanceInfo(單路徑誘導資訊)或 RouteGuidanceInfos(多路徑誘導資訊),包含 forkPoint、multiRoadsForkPoints、eventType、ttsContent 等欄位
- 請求欄位:請求引數(如 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_type 和 eventType,看程式碼中實際使用的欄位名 |
diff 中出現 eventType = request->event_type → 確認 proto 中是 eventType |
| designDoc 提到"日誌列印 SetmultiRoadsForkPoints" | 在 diff 中搜索 LOG 或 printf 語句,確認日誌關鍵字 exact match |
diff 中出現 LOG(INFO) << "SetmultiRoadsForkPoints event_type=" → 確認關鍵字 |
| designDoc 提到"灰度開關 fix_eventtype5" | 在 diff 中搜索 apollo 或 GetConfig,確認 Apollo Key 完整名稱 |
diff 中出現 GetConfig("fix_eventtype5_parseforkpoint_gray_switch") → 確認 Key |
designDoc 提到新增欄位 fork_points |
在 diff 中搜索 fork_points,若程式碼中只有 forkPoint 和 multiRoadsForkPoints → 禁止虛構 fork_points |
校驗規則:
- 若 designDoc 中的欄位名/關鍵字與 diff 中的程式碼實現不一致,以程式碼實現為準
- 若 designDoc 中未提及但 diff 中發現新增欄位/開關,在測試方案中標註為新增,並納入欄位來源表
- 若 diff 中也找不到對應欄位,標註 [待確認: 需開發確認]
6. 欄位不在現有來源表中的處理(新欄位發現流程)
若搜尋到的欄位不在當前欄位來源表中,說明可能是新引入的欄位,執行:
sourceFiles 和 diff 內容,確認該欄位是否在本次變更中新增若是已有欄位但來源表遺漏 → 補充到來源表
新欄位確認流程:
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注入。
[新增欄位: 待 LLM-Wiki 同步],但不影響測試方案生成7. 標記不確定項:若 PRD 或 designDoc 中提到的概念無法對映到協議欄位(如"版本切換"、"已走過的 link"),禁止直接虛構欄位名,應:
- 優先尋找協議中可間接表徵該狀態的欄位
- 若找不到,在 trigger_condition 中使用最相關的真實欄位(如 eventType == 5),並在說明中備註"版本切換狀態通過響應差異反推"
- 絕不能使用 C++ 內部變數名(如 route_has_version_switch、has_traveled_links)作為測試依據
8. 欄位命名規範:嚴格使用 proto 檔案中的欄位名(區分大小寫,如 eventType 而非 event_type)
規則 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_behavior 和 affected_fields 中的欄位必須是響應訊息(Response)中實際存在的欄位
- 禁止將 C++ 內部變數、臨時計算量、未序列化的記憶體物件作為測試依據
- 若需求描述中的概念無法直接對映到協議欄位,應使用最接近的真實欄位,並在場景說明中解釋對映關係
示例場景:
### S001: F 路口提前播報
- **觸發條件**: `scene_type == F_FORK && distance_to_fork <= 150m`
- **預期行為**: `ttsContent` 包含 "前方路口",提前 50m 播報
- **受影響欄位**: `ttsContent`, `voiceType`
- **測試型別**: diff
- **優先順序**: P0
為每個 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 使用。
根據以下因素評估:
| 因素 | 高風險表現 |
|---|---|
| 改動範圍 | 核心演算法、多模組聯動 |
| 影響面 | 全量使用者、全場景 |
| 欄位型別 | 語音播報、安全相關事件 |
| 歷史穩定性 | 同類改動曾引發線上問題 |
風險等級與 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
輸出路徑:<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)"}
]
}
- type:none(無實驗)/ ab_test / grayscale
- groups:diff 分組列表,每組含 name、driver_id、desc
- 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等日誌輸出語句,提取實際日誌格式。若原始碼不可讀或未找到相關日誌,則標註[待確認: 需開發確認]。7w4.net小蔥技能站,你的AI助手技能庫。
模板檔案位置:testing/test-plan-writer/test-plan-template.md
生成完成後,AI 自檢以下項。以下檢查項為阻塞項,任一項未通過必須修正後方可輸出:
feature 欄位與目錄名一致test_scenarios 非空,每個場景有完整欄位data_filter_conditions 與 test_scenarios 一一對應data_filter_conditions 中的欄位均為請求協議中實際存在的欄位(無 C++ 內部變數)功能開關控制 完整(開關型別、白名單/實驗組資訊)測試策略 已根據變更型別自動判斷(Diff / 功能 Case / 迴歸 / 壓測),且判斷依據明確required_phases 與測試策略一致risk_level 評估有依據diff_config 中每個 diff 型別場景都有對應的預期差異定義(含場景ID、欄位、基線值、目標值、變化方向)UNCHANGED(與基線一致)sourceFiles 非空或 git diff HEAD 可執行,已從 diff 中提取實際日誌關鍵字和 Apollo Key;禁止在已執行 diff 分析的情況下仍標註 [待確認: 需開發確認]expected_behavior 包含具體數值、狀態或範圍;無"正常"、"有效"、"正確"等模糊描述;若無法量化,說明中已寫明量化困難原因和替代驗證方式trigger_condition 中無無法從請求欄位推斷的內部狀態trigger_condition 中的欄位均在請求協議中存在;expected_behavior / affected_fields 中的欄位均在響應協議中存在;無虛構欄位;欄位名大小寫與 proto 一致[待確認: 需開發確認] 或已讀取原始碼/diff 確認[待確認: 需開發確認] 或已從 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_conditions 與 test_scenarios 一一對應data_filter_conditions 中的篩選欄位均為請求協議中實際存在的欄位required_phases 包含 Phase 1(自身)risk_level 評估有依據(引用改動範圍或影響面)篩選對映表 中每條預期差異都有場景對應trigger_condition 欄位均為請求協議欄位,expected_behavior / affected_fields 欄位均為響應協議欄位[待確認: 需開發確認]校驗失敗處理: 1. 標註具體失敗項和原因 2. 返回對應 Step 修正 3. 重新校驗直至全部通過
| 產物 | 路徑 |
|---|---|
| 測試方案 | <CASE_DIR>/<feature>/test_plan.md |
這個 Skill 質量很好,文件詳細、邏輯清晰、使用方便。做得好的地方:步驟流程完整、檢查清單詳細、有現成的模板和示例;做了很多質量把關措施,能避免常見錯誤。不足之處:依賴內部服務地址、不方便在外部使用;有些細節說明分散在多處,查詢不夠方便。總體來說,這是一個專業度高、實用性強的 Skill。