验收标准与测试规范。50 个子 Agent 测试工程师的验收依据。 最后更新:2026-04-22
| 层级 | 目标 | 工具/方法 |
|---|---|---|
| 单元测试 | 验证单个模块的行为正确性 | go test |
| 集成测试 | 验证多个模块组合后的完整链路 | httptest.Server + go test |
| 端到端测试 | 验证真实厂商 API 转发 | 真实 API Key,小流量 |
| 变异测试 | 验证测试本身是否有效(尤其针对 AI 生成的测试) | Gremlins |
| 负载测试 | 验证性能指标是否达标 | k6 |
在测试过程中,使用以下 Skills 提高测试效率和质量:
| 测试阶段 | 推荐 Skill | 用途 | 调用时机 |
|---|---|---|---|
| 功能测试 | webapp-testing |
Playwright 自动化测试,验证 API 端点和功能流程 | 开发完成后、CI 前 |
| 探索性测试 | dogfood |
系统性遍历应用,发现隐藏 bug 和 UX 问题 | 上线前、灰度期 |
| UI 规范测试 | web-design-guidelines |
验证前端 UI 是否符合 DESIGN.md 规范 | Phase 2 前端开发后 |
| TDD 开发 | test-driven-development |
先写测试再写实现 | 编码阶段 |
触发场景:
- 验证 /v1/chat/completions 端点
- 测试认证流程(API Key)
- 测试限流机制
- 验证流式响应(SSE)
调用示例:
"使用 webapp-testing skill 测试 /v1/chat/completions 端点的流式响应"
触发场景:
- MVP 上线前全面检查
- Phase 2 管理后台上线前
- 发现边缘场景和 UX 问题
调用示例:
"使用 dogfood skill 对 TokenRouter API 进行全面探索测试"
触发场景:
- Phase 2 管理后台 UI 完成后
- 验证 Apple 设计系统落地情况
- 检查可访问性(a11y)
调用示例:
"使用 web-design-guidelines skill 审查管理后台的设计规范合规性"
开发完成
│
├── 单元测试(go test)→ 通过 → 继续
│
├── 集成测试(httptest)→ 通过 → 继续
│
├── API 功能测试 → 调用 webapp-testing
│
├── 端到端测试(真实 API Key)
│
└── 上线前检查 → 调用 dogfood
- 测试外部行为,不测试实现细节
- 优先使用 TDD(先写测试再写实现)
- 使用表格驱动测试(table-driven)
- 对外部依赖 Mock 接口,不 Mock 具体实现
| 模块 | 测试重点 | 最低覆盖率 |
|---|---|---|
| Canonicalizer | 等价输入输出字节必须完全一致 | 100% |
| Chunker | 各种 messages/tools 组合的切分正确性 |
80% |
| Arranger | System 合并、Tool 字母序排序、History 截断 | 80% |
| Hasher | 相同输入输出相同哈希,不同输入几乎不碰撞 | 80% |
| Outbound Adapters | []Block → JSON 的正确还原 |
70% |
| CacheInjector | Anthropic cache_control 注入位置正确 |
80% |
| Dedup | 并发相同请求挂起复用、超时处理 | 80% |
| Auth Middleware | 有/无/错误 API Key 的场景 | 80% |
| RateLimit Middleware | 限流触发与放行 | 70% |
| Proxy | HTTP 转发和 SSE 逐行转发 | 70% |
- JSON key 递归字母序排序
- 嵌套 JSON 对象
- 空值统一处理(
nullvs omit) - 数字固定精度
- Unicode 字符串
- 多余空白符的消除
使用 httptest.Server mock 上游厂商 API,测试完整请求链路。
- OpenAI 入站 → Anthropic 出站
- 发送 OpenAI 格式请求到 TokenRouter
- 验证 mock Anthropic server 收到的请求体格式正确(
system在顶层,cache_control已注入) - 验证 TokenRouter 返回的响应是 OpenAI 格式
- OpenAI 入站 → OpenAI 出站
- 验证透传路径正常
- 验证
Raw字段中的额外参数被保留
- 去重复用链路
- 并发发送两个完全相同的非流式请求
- 验证第二个请求等待并复用第一个的响应
- 验证只向上游发送一次请求
- 认证 + 限流链路
- 无 Key → 401
- 错误 Key → 401
- 超频请求 → 429
- 正常请求 → 200
- SSE 流式链路
- 发送
stream=true请求 - 验证
data:行被逐行正确转发 - 验证
[DONE]标记正常结束
- 发送
E2E 测试在进程内使用 httptest 组装生产级路由链(AuthMiddleware → 可选 RateLimitMiddleware → server.ChatPipeline.Handle),并直接对接真实厂商 API,验证完整 pipeline 在真实网络环境下的行为。详细运行指南参见 E2E 测试指南。
- 使用真实的厂商 API Key
- 限定小流量(Fast Suite 每个场景 1 个请求,Full Suite 每个场景 1-5 个请求)
- 避免在 CI 中自动运行(因依赖外部 API Key)
| Suite | Build Tag | 请求数 | 用途 | 运行命令 |
|---|---|---|---|---|
| Fast | e2e |
2-3 | 开发阶段核心场景快速验证 | make test-e2e-fast |
| Full | e2e_full |
10+ | 上线前边界/并发全量验证 | make test-e2e-full |
日常 go test ./... 不会编译 E2E 测试文件(Go build tag 隔离)。
E2E 测试只验证响应结构,不验证内容:
choices存在且长度 >= 1message.content为非空字符串usage.prompt_tokens > 0- SSE 流包含
data: [DONE]
原因:大模型相同输入可能返回不同内容,内容断言会导致 flaky test。
| 协议 | 验证重点 | 状态 |
|---|---|---|
| DeepSeek | OpenAI 兼容转发正常,响应格式正确,流式/非流式均通过 | MVP v0.1 |
| Anthropic | cache_control 注入后,usage.cache_*_tokens 非零 |
Phase 1.1 |
| OpenAI | 基础转发正常,响应格式正确 | Phase 1.1 |
- 非流式请求成功返回(DeepSeek V4 Flash)
- 流式请求成功返回完整 SSE(DeepSeek V4 Flash)
- 带 tools 的请求被上游正确接受(非流式)
- 流式 + tools 组合请求正常返回 SSE(
TestFullStreamingWithTools) - system + user 多块消息正确转发(
TestFullSystemPrompt) - 相同请求第二次走 dedup 缓存、两次均返回有效响应(
TestFullDedup) - 畸形 JSON body 被拦截返回 400(
TestFullMalformedBody) - 并发 5 路请求全部返回 200(
TestFullConcurrent) - API Key 认证生效:缺失/无效/已撤销 key 返回 401,合法 key 可调用真实上游
- RateLimit 生效:隔离小限额路由中,同一认证用户第 N+1 次请求返回 429
- 两个结构相同的请求前缀哈希一致(需暴露 metrics/日志后验证)
- Anthropic 缓存命中(通过
usage字段验证) - OpenAI 基础转发正常,响应格式正确
k6
scripts/loadtest.js(计划位置)
| 指标 | MVP 目标 | 测试方法 |
|---|---|---|
| P99 延迟增加 | < 100ms | 不含厂商响应时间,使用 mock server |
| 吞吐量 | > 500 req/s | 逐步加压至稳定状态 |
| 错误率 | < 0.1% | 持续运行 5 分钟 |
- 模拟 Chunker 失败 → 验证透传原始请求
- 模拟 CacheInjector 失败 → 验证无缓存标记继续转发
- 模拟上游厂商超时 → 验证返回 504
在 internal/*/testdata/ 或 tests/fixtures/ 中维护:
- 标准 OpenAI 请求体(含 tools、不含 tools、多轮对话)
- Anthropic 期望的请求体
- 各种边界 messages 组合
make seed(计划中)应生成测试用的 API Key 和用户配额
代码合并前必须通过:
-
go test ./... -race全部通过 -
go vet ./...无警告 - 单元测试覆盖率满足上表最低要求
- 集成测试全部通过
- PR 变更涉及核心模块(Canonicalizer / Hasher / Auth)时,变异分数 ≥ 85%
- PR 变更涉及其他模块时,变异分数 ≥ 75%(或不低于合并前基线)
E2E 测试、变异测试全量扫描和负载测试不要求在 CI 中自动运行,但必须在发布前手动执行并生成报告。变异测试的 CI 门禁使用 gremlins unleash --diff-origin main,只测 PR 变更的代码,运行时间约 2-5 分钟。
以下条件全部满足,方可宣布 MVP 完成:
- 支持 OpenAI 格式入站,DeepSeek V3.2 出站(架构已预留 Anthropic / OpenAI 扩展位)
- 两个结构相同但来源不同的请求,前缀哈希一致
- 并发非流式相同请求能触发去重复用
- P99 延迟增加 < 100ms(不含厂商响应时间)
- 至少 1 个真实用户在生产环境跑通
- 完成 50 个子 Agent 测试工程师的验收
tokenrouter/
├── internal/
│ ├── chunker/
│ │ ├── chunker_test.go
│ │ └── testdata/
│ ├── arranger/
│ │ └── arranger_test.go
│ ├── canonicalizer/
│ │ └── canonicalizer_test.go
│ └── ...
├── tests/
│ ├── integration/
│ │ └── forward_test.go # httptest mock-based 集成测试
│ └── e2e/
│ ├── helper_test.go # pipeline 组装 + 公共断言(e2e || e2e_full)
│ ├── fast_test.go # Fast Suite(//go:build e2e)
│ └── full_test.go # Full Suite(//go:build e2e_full)
└── scripts/
└── loadtest.js # k6 负载测试脚本(计划中)
背景:TokenRouter 大量测试由 AI Agent 生成。AI 生成的测试存在"对称错误"风险——测试和实现犯同一种错误,覆盖率 100% 但测试无效。变异测试是唯一能系统性检测此问题的手段。
Gremlins,专为 Go 微服务设计。
# 安装
brew install go-gremlins/tap/gremlins
# 运行(只测 PR 变更,CI 推荐用法)
gremlins unleash --diff-origin main
# 运行(指定包,本地调试)
gremlins unleash --coverpkg ./internal/canonicalizer/...| 模块 | 最低变异分数 | 备注 |
|---|---|---|
| Canonicalizer | 95% | 字节级正确性,任何偏差都会破坏哈希一致性 |
| Hasher | 90% | 静默错误难以排查 |
| Auth Middleware | 85% | 安全相关 |
| Chunker | 80% | 切分逻辑错误静默传播 |
| Arranger | 80% | 影响缓存命中率 |
| Dedup | 80% | 并发逻辑危险 |
| Outbound Adapters | 75% | 格式错误会被上游 400 拒绝 |
- 分析变异类型(条件取反、语句删除、返回值替换等)
- 补充边界测试——针对 LIVED 的那一行写断言具体值的测试
- 标记等价变异体——对日志、metrics 等无逻辑副作用的 LIVED,加
//gremlins:ignore注释跳过
详细操作步骤见 变异测试指南。