Skip to content

DeepSeek Harness 是一个大型 pnpm monorepo(49 个插件组、219 个包层包),驱动真实的 LLM、子进程、文件系统与浏览器 GUI。出色的测试是工程的一等公民:仓库把验证任务组织成若干层级(tier),每层有各自的 Vitest 配置、测试位置约定与环境规则。本页完整梳理该矩阵——从单文件 100% 覆盖率的单元测试,到无密钥快照回放与真实 API e2e 冒烟测试——并剖析共享的 test-support 包与 DSH_SNAPSHOT 录制/刷新工作流。

测试层级一览

层级命令(package.json配置测试存放位置需要密钥?
单元pnpm run testvitest.config.tspackages/*/*/tests/**/*.spec.tsapps/*/testsexamples/*/testsscripts/**/*.spec.ts
覆盖率门禁pnpm run test:coveragevitest.config.ts(含 coverage)同单元
真实 API e2epnpm run test:e2evitest.e2e.config.ts**/*.e2e.ts是(无密钥自跳过)
无密钥快照pnpm run test:snapshotvitest.snapshot.config.ts**/*.snapshot.ts
Web 浏览器快照pnpm run test:webvitest.web.config.tsapps/web/tests/*.{e2e,snapshot}.ts否(回放)
Web 性能 / 压力test:web:perftest:web:stressvitest.web.{perf,web-stress}.config.tsapps/web/tests/*.perf.tsapps/web/stress-tests/*.stress.ts

根目录 package.jsonscripts 是权威清单。pnpm run test 直接运行 vitest run;各层通过 --config 使用独立配置。这并非单个大 runner——真实 API 测试需要密钥与很长的超时,快照测试在 CI 下绝不能意外写入 golden 文件,浏览器测试要启动整个 Chromium 实例。

test-support

共享机制位于 packages/test-support/。每个包还带一个 ./invariant 伴生包(一个指向 lib/invariant.js 的 npm 子路径导出),使其包所有权登记进不变量注册表——test-support 包通常带有空安装器,并附 No runtime invariant: 注释。

作用
@deepseek-ai/dsh-agent-loop-testkit在 agent-loop 测试前挂载前置服务
@deepseek-ai/dsh-llm-mock-server可脚本化的 OpenAI 兼容 HTTP/SSE 故障服务器
@deepseek-ai/dsh-llm-replay回放插件:从录制的会话 JSONL 重建模型分块
@deepseek-ai/dsh-client-test-runtimejsdom “插槽”运行时:真实 Cordis Context + SlotRegistry + web-react 渲染器
@deepseek-ai/dsh-loader-smoke无密钥示例冒烟的子进程与直连 agent 夹具
@deepseek-ai/dsh-acp-snapshotACP 快照套件工厂、子进程启动器、归一化器

agent-loop-testkit

testkit 挂载 agent loop 本身——只挂载具体 loop 需要的前置服务,从而让测试掌握加载顺序与拓扑:

ts
// packages/test-support/agent-loop-testkit/src/index.ts
import AgentRegistry from '@deepseek-ai/dsh-agent'
import LlmRuntime from '@deepseek-ai/dsh-llm'
import SessionStore from '@deepseek-ai/dsh-session'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRuntime from '@deepseek-ai/dsh-tools'

export async function mountAgentLoopTestDependencies(
  ctx: Context,
  options: AgentLoopTestDependenciesOptions = {},
): Promise<void> {
  await ctx.plugin(LlmRuntime)
  await ctx.plugin(SessionStore)
  await ctx.plugin(SystemPrompt, options.systemPrompt ?? {})
  await ctx.plugin(ToolRuntime, options.tools ?? {})
  await ctx.plugin(AgentRegistry)
}

llm-mock-server

@deepseek-ai/dsh-llm-mock-server 是一个用于 LLM 恢复测试的可脚本化故障服务器。因为它是 HTTP/SSE 服务器,所以能覆盖真实传输,并针对真实故障模式做加固——connection_resetstream_disconnectpartial_eofstallmalformed_eventrate_limitauth_errorcontext_overflowquota_exceeded 等等:

ts
// packages/test-support/llm-mock-server/src/index.ts
export const MOCK_LLM_BEHAVIORS = [
  'connection_reset', 'stream_disconnect', 'empty', 'empty_body',
  'stream_eof', 'partial_eof', 'partial_disconnect', 'stall',
  'malformed_json', 'malformed_event', 'wrong_content_type', 'rate_limit',
  'server_error', 'service_unavailable', 'auth_error', 'invalid_request',
  'context_overflow', 'quota_exceeded', 'success', 'reasoning_success',
  'tool_call_success', 'max_tokens', 'slow_success', 'random',
] as const

llm-replay

@deepseek-ai/dsh-llm-replay 是快照测试无密钥方案的核心。它读取录制的会话 JSONL,从 assistant/chunk 事件为每个会话推导一个模型调用脚本,并按首次调用顺序把新的实时会话绑定到这些脚本——于是测试用回放的模型输出启动 真实的 agent loop:

ts
export type ReplayEntry =
  | { kind: 'chunks'; chunks: StreamChunk[] }
  | { kind: 'throw'; chunks: StreamChunk[]; message: string; code: string }
  | { kind: 'hang'; readyFile?: string }

acp-snapshot

@deepseek-ai/dsh-acp-snapshot 构建无密钥的 ACP 场景。每个场景驱动真实子进程(启动 acp-agent 示例)并比较归一化后的 stdout;会话 fixture 同时充当回放输入与预期输出。

client-runtime 与 loader-smoke

  • @deepseek-ai/dsh-client-test-runtime 提供 jsdom“插槽”运行时——真实的 Cordis Context + SlotRegistry + web-react 渲染器——外加测试专属的 session/workspace 双例,因此客户端功能规格测试无需浏览器进程就能运行。
  • @deepseek-ai/dsh-loader-smoke 是无密钥真实 Loader 示例冒烟的共享子进程/直连 agent 夹具。每个示例都附带一个无密钥冒烟测试:通过 Loader 启动真实 cordis.yml,驱动它,并断言输出与干净退出。

DSH_SNAPSHOT 工作流

快照配置从 DSH_SNAPSHOT 环境变量选择模式。package.json

jsonc
"test:snapshot":           "vitest run --config vitest.snapshot.config.ts",
"test:snapshot:record":    "DSH_SNAPSHOT=record vitest run --config vitest.snapshot.config.ts --update",
"test:snapshot:refresh":   "DSH_SNAPSHOT=refresh vitest run --config vitest.snapshot.config.ts"

三种模式(来自 vitest.snapshot.config.ts):

模式效果并行?
replay(默认)从录制响应启动真实子进程路径;比对汇编请求、归一化输出与持久化日志 golden。绝不写已提交输出。并行
record调用真实 API(加载 .env 取密钥)并更新 fixture 与预期输出。串行
refresh回放已提交脚本,只重写衍生的预期输出(无需密钥)。串行

模型转录发生变化时用 record;回放输入仍有效、但预期输出变了时用 refresh。务必审阅每一处 JSONL 与预期输出 diff。refresh 刻意保持串行——并发写回会破坏从磁盘 fixture 采集 golden 的过程(--update 意味着写入)。Web 层在 CI 中强制 DSH_SNAPSHOT=replay(只读),确保一次提交绝不会悄悄改动预期输出。

源码平面解析

每个 Vitest 配置都把 vite-tsconfig-paths 指向 tsconfig.base.json(无 include → 匹配一切)。因此裸 workspace 导入解析到 src绝不经包 exports 落到构建出的 lib/——那里的陈旧产物会加载第二份模块单例。构建产物只在 lib 模式子进程与构建产物冒烟测试(packages/examples/*/tests/built-bin.e2e.ts)中被显式消费。

共享的装饰器预变换(vitest.shared.ts 中的 standardDecoratorPlugin)在 Vite 解析前编译标准 TypeScript 装饰器;vitestExecArgv 传入 --no-webstorage,使进程级 Web Storage 不会遮蔽 jsdom 存储。

覆盖率:单文件 100%

vitest.config.tspackages/*/*/src/** 上设置 thresholds: { perFile: true, statements: 100, branches: 100, functions: 100, lines: 100 }。未覆盖的一行通常是门禁正确地标记出来该删除的死代码——而非缺失的测试。coverage 的 exclude 列表豁免纯类型文件、自启动的 bin.ts/worker.ts 入口,以及一组带 TODO(gui) 债务标注的客户端/UI 文件。pwsh-local 文件仅在宿主无真实 pwsh 时豁免(通过 spawnSync(resolvePwshPath(), …) 探测)。

真实 API e2e 与 with-key 政策

docs/testing.md 明确阐述了该理念:“We are DeepSeek — do not ration real-API tests.”(我们就是 DeepSeek——不要吝啬真实 API 测试。)无密钥测试只证明管道通;只有带密钥的运行才能证明 agent 对真实模型真的有效。最高价值的是冒烟测试:启动真实示例、发一条提示、检查外部世界(外部状态),而不是模型的自述。每个 e2e 套件使用 DEEPSEEK_API_KEY 或各 providers 的密钥(EXA_API_KEYPERPLEXITY_API_KEY,…),无密钥时自跳过,从而让无密钥 CI 与无密钥贡献者保持绿色。vitest.e2e.config.ts 设置 testTimeout: 120_000retry: 2 与受限的工作池(DSH_E2E_MAX_WORKERS,默认 4)。

test-invariants setup 与 HMR 安全

主要配置都注册 setupFiles: ['./scripts/test-invariants.ts'](三个 web/浏览器配置不注册),且每个注册表测试都含 HMR 安全断言(dispose 贡献 fiber,断言清理)。不变量理念在运行时不变量页中有完整讨论。

延伸阅读

  • 运行时不变量— 你的测试依托的断言理念。
  • CI 与发布— 各层如何变成绿色 PR 门禁(check:ci:*)。
  • 官方 docs/testing.md— 分层政策与 with-key / 真实入口路径规则,都在仓库里。
  • 官方 docs/defensive-patterns.md— 测试必须钉住的 bug 类规则。
  • packages/test-support/README.md— 六个 test-support 包的伞形说明。
  • scripts/run-gates.ts— 在 CI 中编排各层的 check:ci:* 脚本。