CHAPTER 13 · STAGE 03 · 理解可靠性与扩展
测试体系与完成一次真实改动
修改一个纯函数,只需要聚焦单元测试可能已经足够。修改模型可见输出,仅有单元测试不够,因为真实组合中的提示词、工具 schema、持久日志和协议输出可能仍然错误。测试不是越多越好,而是证据要匹配行为层级
修改一个纯函数,只需要聚焦单元测试可能已经足够。修改模型可见输出,仅有单元测试不够,因为真实组合中的提示词、工具 schema、持久日志和协议输出可能仍然错误。
仓库要求根据改动表面选择证据:行为逻辑看聚焦测试,真实插件组合看 Loader 或 e2e,模型或用户可见输出看 keyless snapshot,Provider 行为看真实 API e2e,发布入口看 built artifact smoke。
单元测试
pnpm run test 使用 Vitest 运行包和示例旁边的 spec。单元测试适合边界条件、错误分支、事件顺序、并发竞态和回归行为。
Registry 需要 HMR 安全测试:挂载贡献插件,验证注册存在;卸载对应 fiber,验证贡献完全清理。只测注册成功,无法证明插件生命周期正确。
运行聚焦测试时直接给文件路径:
pnpm run test -- packages/core/agent-loop/tests/loop.spec.ts
先运行与你改动直接相关的少量测试,不要默认执行全仓库所有检查。
Coverage Gate
pnpm run test:coverage 是 CI 覆盖率门槛,对 packages/*/*/src 按文件要求 100%。普通 test 通过不等于 coverage gate 通过。
覆盖率只说明代码行被执行,不说明产品真的正确。无法自然覆盖的代码有时是应该删除的死代码,而不是强行写一个没有行为意义的测试。
真实组合测试
产品可见插件需要通过真实 Loader 配置和实际入口路径组合。手工 ctx.plugin() 可以验证局部 API,却可能漏掉 export、cordis.yml、依赖 manifest、inject 和加载顺序问题。
真实组合测试应保留真实 Tool、Provider 和下游实现,只 mock 昂贵或非确定边界,例如 LLM、网络和时钟。
“真实”不等于必须调用付费模型。Replay Adapter 或脚本化 Mock LLM 可以驱动真实 AgentLoop、工具和 Session。
Keyless Snapshot
非平凡的模型、协议或用户可见变化需要更新 runnable example 的 keyless snapshot。Snapshot 启动真实组合,重放录制 Session,再比较规范化协议输出或持久日志。
它能发现“单包测试通过,但最终提示词、工具 schema 或 UI 输出不对”的问题。
使用 record 会重新调用真实模型并录制输入,refresh 则在 replay 输入仍有效时刷新预期输出。所有 JSONL 和 expected diff 都需要人工审查。
Real-API E2E
真实 Provider 行为只能由真实 API 证明。pnpm run test:e2e 在没有相应 Key 时自跳过,有 Key 时运行真实模型、搜索或沙箱服务。
高价值用例是从真实入口发一个任务,再从外部检查文件或命令结果,而不是只相信 Agent 回答“我已经完成”。
Built Artifact Smoke
源码通过 tsx 运行不代表发布包能在普通 Node 下运行。package bin、worker entry 和 exports 需要构建后的 lib/ smoke。
当改动影响发布入口时先 pnpm run build,再运行对应 built test。不要让源码 paths map 掩盖 package exports 或 ESM 问题。
Source Plane 与 Artifact Plane
静态检查和普通测试通过 tsconfig paths 解析到 src,要求在干净构建目录也能运行。使用构建产物的检查必须显式声明先 build。
如果测试偶然读取旧 lib/,可能加载同一个模块的第二份 singleton,造成只在本机出现的诡异结果。测试配置因此统一指向源码 plane。
一次小改动的推荐流程
1. 找拥有行为的包
不要从搜索到的第一个调用点修改。先判断 Definition、Provider、Consumer、策略或入口谁拥有该规则。
2. 写失败测试
测试描述期望行为和外部结果。先看它在当前实现上失败,证明测试能捕获问题。
3. 做最小实现
优先挂现有扩展点。新增能力要完成 Definition、Provider、Consumer 三种角色;不要为了方便给 AgentLoop 加业务分支。
4. 更新文档
代码改动同步更新 owning README 和公开 JSDoc。模型可见行为说明 What the model sees、Token effect 和 KV Cache effect。
非平凡改动还要在同一 PR 添加或更新 Agent Note,记录当前机制、取舍与验证,而不是写实现过程日记。
5. 运行最小充分检查
先跑聚焦测试;模型可见行为跑 snapshot;文档跑 doc-sync;发布路径需要 build/hygiene;真实 Provider 行为跑相应 e2e。
怎样写一个好测试
测试名描述行为,不写“correctly”之类空词。断言外部可观察结果,而不是重复实现内部变量。
取消与 teardown 测试要等待资源收敛,验证 Registry 清理、进程退出或 handle dispose 完成。并发测试要控制时序,避免靠不稳定 sleep 猜测事件发生。
模型文件修改任务要重新读取文件,验证实际内容,并确认不应改变的文件字节保持不变。
文档检查
学习目录是单语个人教材,不进入正式双语 pairing,但仍要保持 Markdown 链接有效、段落一行、代码块闭合和尾部换行。
正式文档改动需要遵守 docs/AGENTS.md,配对文件必须同时更新并重新记录 pairing。生成目录不能手改,应修改 owner 或 generator source。
第一个贡献应该选什么
适合初学者的范围:改进一个已有错误信息;给一个小 Registry 增加明确的卸载测试;修复一个局部配置校验;给简单 Tool 增加一个边界测试;补充一个真实但范围明确的 README 限制。
暂时不要把第一个任务选成重写 AgentLoop、替换 Session 格式、设计新的远程协议或修改跨平台进程树。这些需要深入生命周期和兼容性知识。
本篇练习
- 为“Tool 参数校验错误文本改变”选择需要的测试层级。
- 为“Headless 最终输出改变”选择测试层级。
- 为“DeepSeek Adapter 解析一种新 chunk”选择 unit、snapshot 和 real API 中的必要组合。
- 打开
docs/testing.zh.md,找到真实入口与 snapshot 的要求。
验收标准:看到一个 diff 时,能说明每个测试命令证明什么,也能明确它没有证明什么。