用 gstack Testing Specialist 清单做系统化测试缺口审查:把「没测到」变成可复现的代码评审结论
导读
本文讲解 gstack 中 Testing Specialist Review Checklist 这份评审专家清单:它定义了一个专职审查测试质量的 AI 子代理,在合入前的代码评审(/review,即 Pre-Landing Review)中对 diff 进行六类系统性扫描,找出「新错误处理路径没有测试」「边界值没有覆盖」「测试相互污染」「测试偶发失败」「安全强制逻辑无验证」「覆盖率空洞」等问题,并以机器可解析的 JSONL 输出协议逐条产出结论。读完本文,你将掌握这份清单的完整检查范畴、JSON 输出 Schema 的每个字段语义、它如何与 gstack Review Army 并行子代理体系协同(含测试桩 test_stub 的生成与去向),以及仓库中对应的端到端测试如何验证这一机制。
一、定位:Testing Specialist 是 /review 的常驻专家
gstack 的 review/SKILL.md 将合入前评审组织为多道关卡:Step 4 的主检(Critical Pass + Informational 分类)覆盖 SQL 与数据安全、竞态条件、LLM 输出信任边界等结构化风险;Step 4.5 则启动 Review Army(评审军团),向若干专职子代理(specialist)分发各自领域的检查清单。
Testing Specialist 在其中处于默认常驻的位置。依据 review/SKILL.md 的调度规则,当 diff 变更行数 ≥ 50 时,有两个专家每次评审必派:
- Testing —— 读取 review/specialists/testing.md
- Maintainability —— 读取
review/specialists/maintainability.md
对应的分支逻辑在源码中写作:
Always-on (dispatch on every review with 50+ changed lines):
1. Testing — read review/specialists/testing.md
2. Maintainability — read review/specialists/maintainability.md
当 DIFF_LINES < 50 时则不派发任何专家,直接输出 "Small diff (N lines) — specialists skipped." 并进入 Step 5。Testing Specialist 自己的文档头部把适用范围标注为 "Always-on (every review)",而 Review Army 的整体调度对它做了「小 diff 不派发」的现实约束,避免为一行改动付出子代理成本。
除此之外还有按作用域信号条件派发的专家:Security(SCOPE_AUTH=true 或后端改动超 100 行)、Performance、Data Migration、API Contract、Design 等,各有独立清单文件,例如 review/specialists/security.md。这些专家通过 Agent 工具并行启动(在一条消息中发起多个 Agent 调用),每个子代理拥有全新上下文,不带主检的先入之见。
二、输出协议:JSONL Finding 与 NO FINDINGS 哨兵
Testing Specialist 的输出不是散文,而是严格的一段 JSON 一行(JSONL)。整份清单第 4-7 行定义了协议:
{"severity":"CRITICAL|INFORMATIONAL","confidence":N,"path":"file","line":N,"category":"testing","summary":"...","fix":"...","fingerprint":"path:line:testing","specialist":"testing"}
字段语义逐项拆解:
| 字段 | 必填 | 取值/格式 | 含义 |
|---|---|---|---|
severity |
是 | CRITICAL 或 INFORMATIONAL |
严重度:导致缺陷外泄的为 CRITICAL,质量改进型为 INFORMATIONAL |
confidence |
是 | 1–10 整数 | 置信度,纳入统一校准体系(9–10 正常展示;5–6 需附 caveat;3–4 移入附录;1–2 除非 P0 否则不报) |
path |
是 | 文件路径 | 问题所在文件 |
line |
否 | 行号 | 问题行号 |
category |
是 | testing |
该专家所有 finding 的类别固定为 testing |
summary |
是 | 一句话 | 问题描述 |
fix |
否 | 一句话 | 建议修复 |
fingerprint |
否 | path:line:testing |
去重指纹,用于跨专家、跨评审轮次的查重 |
specialist |
是 | testing |
来源专家标识 |
evidence |
否 | 证据文本 | 佐证材料 |
test_stub |
否 | 测试骨架代码 | 能捕获该问题的测试桩,见下文第五节 |
协议还有一条硬性纪律:如果没有发现任何问题,只输出 NO FINDINGS,不要输出任何其他内容——不能有前言、不能有总结、不能有注释性旁白。这与 review/checklist.md 中 "No compliments — just the problems" 的原则一致,保证下游解析器(Step 4.6 按行解析 JSON)能稳定消费输出。
三、六大审查范畴详解
Testing Specialist 的检查主体是六类测试缺陷,每类包含一组可操作的判别点。以下结合仓库上下文逐一展开。
3.1 Missing Negative-Path Tests(缺少负路径测试)
只测了「应该成功」,没测「应该失败」。这是测试体系最常见的系统性空洞。
判别点包括:
- 新增的错误/拒绝/非法输入处理路径没有任何对应测试——写了错误分支却从不验证它触发;
- Guard clause(守卫子句)和早期 return 未测试——
if invalid then return这类提前退出常常是「从未执行过的死逻辑」; - try/catch、rescue、错误边界(error boundary)中的错误分支没有失败路径测试——只覆盖 try 的成功流;
- 代码中断言的权限/认证检查,从未测试「被拒绝(denied)」那一侧——见第六节「安全强制测试缺失」。
仓库的端到端测试对此有直接验证。在 test/skill-e2e-review-army.test.ts 的 Consensus 场景(第 494-559 行)中,构造了一个存在 SQL 注入的认证控制器(AuthController#login 用字符串插值拼 User.find_by),场景说明明确指出该漏洞应当被两个专家同时捕获:Security 专家看到注入向量,Testing 专家看到「认证绕过没有测试」。评审输出中若同一 finding 被多视角同时命中,须标记为 MULTI-SPECIALIST CONFIRMED 并列出确认的类别。
3.2 Missing Edge-Case Coverage(缺少边界用例覆盖)
判别点包括:
- 边界值:零、负数、
max-int、空字符串、空数组、nil/null/undefined; - 单元素集合——循环上的 off-by-one(差一错误)常在空集合与单元素集合处暴露;
- 面向用户输入中的 Unicode 与特殊字符——emoji、组合字符、控制字符、超长串;
- 并发访问模式没有竞态测试——见主清单中竞态类别(如 check-then-set、无唯一索引的 find-or-create)的测试侧补充。
这些边界值检查与 review/checklist.md 的 Completeness Gaps 类别互相呼应:后者要求对「增加缺失测试只需照抄 happy-path 结构的 lake 而非 ocean」型缺口给出提示,而 Testing Specialist 负责在代码层面把这类缺口逐一指认。
3.3 Test Isolation Violations(测试隔离违规)
一个测试的结果偷偷取决于另一个测试先跑了什么。今天绿,明天红,随机化顺序就红。
判别点包括:
- 共享可变状态的测试:类变量(class variables)、全局单例、不清理的数据库记录;
- 顺序依赖测试:按顺序跑通过,随机化后失败;
- 依赖系统时钟、时区或 locale 的测试——换台机器或换个时区就崩;
- 发真实网络请求而不是用 stub/mock 的测试。
3.4 Flaky Test Patterns(偶发失败模式)
判别点包括:
- 时序断言:
sleep、setTimeout、waitFor配过紧的 timeout——在 CI 慢机器上必现的假阳性源; - 对无序结果做顺序断言:hash 键序、
Set迭代序、异步解析完成序都不可靠; - 依赖外部服务(API、数据库)且无 fallback 的测试;
- 随机测试数据无种子(seed)控制——复现不了就修不了。
3.5 Security Enforcement Tests Missing(缺少安全强制测试)
这条是「负路径测试」在安全维度的特化,判别点包括:
- 控制器中的 auth/authz 检查没有「未授权」用例测试;
- 限流逻辑没有能证明它确实会拦截(blocks)的测试;
- 输入净化没有恶意输入测试;
- CSRF/CORS 配置没有集成测试。
正如清单所说,这类缺陷与主检 Pass 1 的「信任边界」视角互为表里:主检负责发现代码层的漏洞模式,Testing Specialist 负责发现「防护已经写上去了、但从未被测试证明有效」的隐患。Security 专家与 Testing 专家在此处高度互补——review/specialists/security.md 专注抓 authz 绕过与攻击面扩张的实现缺陷,Testing 清单则追「denied / unauthorized / malicious」这些反面用例是否存在。
3.6 Coverage Gaps(覆盖率空洞)
判别点包括:
- 新增公开方法/函数测试覆盖为零;
- 被修改的方法,既有测试只覆盖旧行为、没覆盖新分支——最典型的回归漏网点;
- 被多处调用的工具函数只被间接测试——直接路径没有断言,行为漂移不会被发现。
从源码结构看,这一条特别契合 gstack 自述的 Completeness Principle(Boil the Ocean) 哲学:AI 让完整覆盖变得廉价,因此「完整版」才是目标——新增公开方法应当有直接测试,改动的方法应当补新分支用例,多调用点工具函数应当有面向契约的直接测试,而非依赖偶然的间接覆盖。
四、六类问题之外的元约束:依赖主检的职责边界
Testing Specialist 不是万能的。它的清单在设计上刻意避开主检(Critical Pass)已经覆盖的 SQL 注入、竞态、LLM 输出信任边界、Shell 注入、枚举完整性等类别——这些由 review/SKILL.md Step 4 的 CRITICAL 通道处理,专家清单则聚焦「测试本身」的缺陷。与之配套的纪律来自主清单 review/checklist.md 的声明:Specialist categories(Test Gaps 等)由并行子代理处理,不属于主检清单,即主检遇到测试缺口类问题时不应在自有输出中重复造轮子。
同时,所有专家 finding 统一接受 review/SKILL.md 的 Pre-emit verification gate(#1539 反假阳性门):凡要进入报告,必须引用触发该结论的具体代码行(file:line + 原文)。若引不出动机行,则视为未验证,置信度强制压到 4-5、只进附录。这同样约束 Testing Specialist——「这个新方法没有测试」的断言必须指出方法定义所在文件与行号,否则不能以高置信度上报。
五、Finding 的旅程:从 JSON 到修复动作
Testing Specialist 输出的每行 JSON 不是终点,而是接入下游流水线:
-
指纹去重与共识加权(Step 4.6):以
fingerprint(缺省回退到path:line:category)分组。若 Security 与 Testing 同时命中同一指纹,保留最高置信度者并标注MULTI-SPECIALIST CONFIRMED,置信度 +1(封顶 10)。这正是 test/skill-e2e-review-army.test.ts 中 SQL 注入 + 认证无测试场景验证的行为。 -
测试桩(test_stub)与框架感知:Testing Specialist 被要求「凡是能写出捕获该问题的测试,就把骨架放进
test_stub字段」——先由 review/SKILL.md Step 4.5 检测测试框架(TEST_FW:jest / vitest / rspec / pytest / go-test,依据jest.config.*、vitest.config.ts、spec/、pytest.ini、go.mod等信号),子代理据此生成describe/it/test骨架。携带test_stub的 finding 会被强制重分类为 ASK(见 Step 5a:Test stub override),呈交用户审批后再落盘,测试文件路径按项目惯例推导(RSpec 用spec/、Jest/Vitest 用__tests__/、pytest 用test_前缀、Go 用_test.go后缀;文件已存在则追加)。 -
Fix-First 分类与动作:参照 review/checklist.md,机械性修复直接 AUTO-FIX,歧义项批量 AskUserQuestion(每项 A) Fix as recommended / B) Skip)。主检里 Critical 偏 ASK、Informational 偏 AUTO-FIX;Testing 专家的多数缺口类 finding 属于可机械补测试的场景,天然落在 AUTO-FIX 侧。
-
质量分与档案:全部合并后计算
quality_score = max(0, 10 - (critical×2 + informational×0.5)),并把每个专家的派发统计(dispatched、findings、critical、informational)与逐条 action 记录(auto-fixed / fixed / skipped)写入 review-log,供/ship识别本分支已完成 Eng Review。
六、把清单用起来:落地建议
- 作为人类 Reviewer 的自查表:六类范畴可直接移植到任何 PR 的测试审查中。实践中最高频命中的是 3.1(守卫子句无负路径测试)与 3.6(改动方法只测旧行为)——建议按 diff 中每个新增
if error分支逐个问「反面用例在哪」。 - 作为测试补充任务清单:对每个
test_stub生成完整用例后,用随机化顺序(如 RSpec 的--order random、Go 的-shuffle)跑一遍即可顺带暴露 3.3 的隔离违规。 - 与安全评审联动:凡 Security 专家报出 authz/限流/净化类实现缺陷时,检查对应反面测试是否已存在;不存在则按 3.5 单独开一条 finding,这正是 Review Army 设计的多专家互补意图。
相关文件索引
- 本清单本体:review/specialists/testing.md
- 派发与合并逻辑、子代理 Prompt、test_stub 重分类:review/SKILL.md
- 主检两类 Pass、Fix-First 分类与专家职责边界:review/checklist.md
- 姊妹清单(作用域条件派发):review/specialists/security.md
- 验证多专家共识与指纹加权的端到端测试:test/skill-e2e-review-army.test.ts
- 专家清单文件装配进临时仓库的测试夹具逻辑:test/skill-e2e-review-army.test.ts
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00