Skip to content

Latest commit

 

History

History
346 lines (253 loc) · 12.5 KB

File metadata and controls

346 lines (253 loc) · 12.5 KB

TokenRouter Test Specification

验收标准与测试规范。50 个子 Agent 测试工程师的验收依据。 最后更新:2026-04-22


1. 测试分层

层级 目标 工具/方法
单元测试 验证单个模块的行为正确性 go test
集成测试 验证多个模块组合后的完整链路 httptest.Server + go test
端到端测试 验证真实厂商 API 转发 真实 API Key,小流量
变异测试 验证测试本身是否有效(尤其针对 AI 生成的测试) Gremlins
负载测试 验证性能指标是否达标 k6

2. AI Skills 辅助测试

在测试过程中,使用以下 Skills 提高测试效率和质量:

2.1 测试 Skills 对照表

测试阶段 推荐 Skill 用途 调用时机
功能测试 webapp-testing Playwright 自动化测试,验证 API 端点和功能流程 开发完成后、CI 前
探索性测试 dogfood 系统性遍历应用,发现隐藏 bug 和 UX 问题 上线前、灰度期
UI 规范测试 web-design-guidelines 验证前端 UI 是否符合 DESIGN.md 规范 Phase 2 前端开发后
TDD 开发 test-driven-development 先写测试再写实现 编码阶段

2.2 Skills 使用场景

webapp-testing

触发场景:
- 验证 /v1/chat/completions 端点
- 测试认证流程(API Key)
- 测试限流机制
- 验证流式响应(SSE)

调用示例:
"使用 webapp-testing skill 测试 /v1/chat/completions 端点的流式响应"

dogfood

触发场景:
- MVP 上线前全面检查
- Phase 2 管理后台上线前
- 发现边缘场景和 UX 问题

调用示例:
"使用 dogfood skill 对 TokenRouter API 进行全面探索测试"

web-design-guidelines

触发场景:
- Phase 2 管理后台 UI 完成后
- 验证 Apple 设计系统落地情况
- 检查可访问性(a11y)

调用示例:
"使用 web-design-guidelines skill 审查管理后台的设计规范合规性"

2.3 测试流程中的 Skills 集成

开发完成
    │
    ├── 单元测试(go test)→ 通过 → 继续
    │
    ├── 集成测试(httptest)→ 通过 → 继续
    │
    ├── API 功能测试 → 调用 webapp-testing
    │
    ├── 端到端测试(真实 API Key)
    │
    └── 上线前检查 → 调用 dogfood

3. 单元测试要求

3.1 测试原则

  • 测试外部行为,不测试实现细节
  • 优先使用 TDD(先写测试再写实现)
  • 使用表格驱动测试(table-driven)
  • 对外部依赖 Mock 接口,不 Mock 具体实现

3.2 按模块的测试重点与覆盖率

模块 测试重点 最低覆盖率
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%

3.3 Canonicalizer 必须覆盖的边界情况

  • JSON key 递归字母序排序
  • 嵌套 JSON 对象
  • 空值统一处理(null vs omit)
  • 数字固定精度
  • Unicode 字符串
  • 多余空白符的消除

4. 集成测试要求

4.1 测试策略

使用 httptest.Server mock 上游厂商 API,测试完整请求链路。

4.2 必须覆盖的链路

  1. OpenAI 入站 → Anthropic 出站
    • 发送 OpenAI 格式请求到 TokenRouter
    • 验证 mock Anthropic server 收到的请求体格式正确(system 在顶层,cache_control 已注入)
    • 验证 TokenRouter 返回的响应是 OpenAI 格式
  2. OpenAI 入站 → OpenAI 出站
    • 验证透传路径正常
    • 验证 Raw 字段中的额外参数被保留
  3. 去重复用链路
    • 并发发送两个完全相同的非流式请求
    • 验证第二个请求等待并复用第一个的响应
    • 验证只向上游发送一次请求
  4. 认证 + 限流链路
    • 无 Key → 401
    • 错误 Key → 401
    • 超频请求 → 429
    • 正常请求 → 200
  5. SSE 流式链路
    • 发送 stream=true 请求
    • 验证 data: 行被逐行正确转发
    • 验证 [DONE] 标记正常结束

5. 端到端测试要求

E2E 测试在进程内使用 httptest 组装生产级路由链(AuthMiddleware → 可选 RateLimitMiddlewareserver.ChatPipeline.Handle),并直接对接真实厂商 API,验证完整 pipeline 在真实网络环境下的行为。详细运行指南参见 E2E 测试指南

5.1 测试环境

  • 使用真实的厂商 API Key
  • 限定小流量(Fast Suite 每个场景 1 个请求,Full Suite 每个场景 1-5 个请求)
  • 避免在 CI 中自动运行(因依赖外部 API Key)

5.2 Suite 分层

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 隔离)。

5.3 断言策略

E2E 测试只验证响应结构,不验证内容:

  • choices 存在且长度 >= 1
  • message.content 为非空字符串
  • usage.prompt_tokens > 0
  • SSE 流包含 data: [DONE]

原因:大模型相同输入可能返回不同内容,内容断言会导致 flaky test。

5.4 必须验证的协议

协议 验证重点 状态
DeepSeek OpenAI 兼容转发正常,响应格式正确,流式/非流式均通过 MVP v0.1
Anthropic cache_control 注入后,usage.cache_*_tokens 非零 Phase 1.1
OpenAI 基础转发正常,响应格式正确 Phase 1.1

5.5 E2E 测试清单(MVP v0.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/日志后验证)

5.6 Phase 1.1 追加清单(Anthropic / OpenAI 接入后)

  • Anthropic 缓存命中(通过 usage 字段验证)
  • OpenAI 基础转发正常,响应格式正确

6. 负载测试要求

6.1 工具

k6

6.2 脚本位置

scripts/loadtest.js(计划位置)

6.3 验收阈值

指标 MVP 目标 测试方法
P99 延迟增加 < 100ms 不含厂商响应时间,使用 mock server
吞吐量 > 500 req/s 逐步加压至稳定状态
错误率 < 0.1% 持续运行 5 分钟

6.4 降级测试

  • 模拟 Chunker 失败 → 验证透传原始请求
  • 模拟 CacheInjector 失败 → 验证无缓存标记继续转发
  • 模拟上游厂商超时 → 验证返回 504

7. 测试数据与 Fixtures

7.1 推荐 Fixtures

internal/*/testdata/tests/fixtures/ 中维护:

  • 标准 OpenAI 请求体(含 tools、不含 tools、多轮对话)
  • Anthropic 期望的请求体
  • 各种边界 messages 组合

7.2 Seed 数据

  • make seed(计划中)应生成测试用的 API Key 和用户配额

8. CI Gate 规则

代码合并前必须通过:

  • go test ./... -race 全部通过
  • go vet ./... 无警告
  • 单元测试覆盖率满足上表最低要求
  • 集成测试全部通过
  • PR 变更涉及核心模块(Canonicalizer / Hasher / Auth)时,变异分数 ≥ 85%
  • PR 变更涉及其他模块时,变异分数 ≥ 75%(或不低于合并前基线)

E2E 测试、变异测试全量扫描和负载测试不要求在 CI 中自动运行,但必须在发布前手动执行并生成报告。变异测试的 CI 门禁使用 gremlins unleash --diff-origin main,只测 PR 变更的代码,运行时间约 2-5 分钟。


9. 50 子 Agent 测试工程师验收清单(MVP)

以下条件全部满足,方可宣布 MVP 完成:

  • 支持 OpenAI 格式入站,DeepSeek V3.2 出站(架构已预留 Anthropic / OpenAI 扩展位)
  • 两个结构相同但来源不同的请求,前缀哈希一致
  • 并发非流式相同请求能触发去重复用
  • P99 延迟增加 < 100ms(不含厂商响应时间)
  • 至少 1 个真实用户在生产环境跑通
  • 完成 50 个子 Agent 测试工程师的验收

10. 测试目录结构

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 负载测试脚本(计划中)

11. 变异测试要求

背景:TokenRouter 大量测试由 AI Agent 生成。AI 生成的测试存在"对称错误"风险——测试和实现犯同一种错误,覆盖率 100% 但测试无效。变异测试是唯一能系统性检测此问题的手段。

11.1 工具

Gremlins,专为 Go 微服务设计。

# 安装
brew install go-gremlins/tap/gremlins

# 运行(只测 PR 变更,CI 推荐用法)
gremlins unleash --diff-origin main

# 运行(指定包,本地调试)
gremlins unleash --coverpkg ./internal/canonicalizer/...

11.2 各模块变异分数目标

模块 最低变异分数 备注
Canonicalizer 95% 字节级正确性,任何偏差都会破坏哈希一致性
Hasher 90% 静默错误难以排查
Auth Middleware 85% 安全相关
Chunker 80% 切分逻辑错误静默传播
Arranger 80% 影响缓存命中率
Dedup 80% 并发逻辑危险
Outbound Adapters 75% 格式错误会被上游 400 拒绝

11.3 处理 LIVED 变异体

  1. 分析变异类型(条件取反、语句删除、返回值替换等)
  2. 补充边界测试——针对 LIVED 的那一行写断言具体值的测试
  3. 标记等价变异体——对日志、metrics 等无逻辑副作用的 LIVED,加 //gremlins:ignore 注释跳过

详细操作步骤见 变异测试指南