
Codebuff SDK 端到端测试实战指南E2E、集成测试与可运行示例全解析【免费下载链接】freebuffThe free coding agent项目地址: https://gitcode.com/GitHub_Trending/cod/freebuffCodebuff SDKcodebuff/sdk为开发者提供了调用 Codebuff AI 编码 Agent 的完整运行时能力。本文围绕仓库中sdk/e2e目录的测试体系展开系统讲解其四层测试结构端到端测试、集成测试、单元测试、可运行示例、环境变量与运行方式、测试工具设施EventCollector、Mock 机制、测试夹具以及标准的测试编写模式。读完本文你将能够直接运行这套测试套件、理解流式事件与子 Agent 流的验证方法并掌握编写属于自己的 SDK E2E 测试的完整套路。一、sdk/e2e目录结构与测试分层sdk/e2e目录是 SDK 的测试与示例集散地核心文档为 sdk/e2e/README.md。整个目录按职责划分为七个子目录sdk/e2e/ ├── streaming/ # E2E 测试流式行为子 Agent 流、并发流 ├── workflows/ # E2E 测试多步骤工作流多轮对话、错误恢复 ├── custom-agents/ # E2E 测试自定义 Agent 与自定义工具集成 ├── features/ # E2E 测试SDK 特性覆盖projectFiles、knowledgeFiles、maxAgentSteps ├── integration/ # 集成测试SDK API 机制 ├── examples/ # 可运行示例脚本不是测试 └── utils/ # 共享工具 ├── __tests__/ # 工具类的单元测试 ├── event-collector.ts ├── get-api-key.ts └── test-fixtures.ts这种分层设计遵循了经典测试金字塔思路E2E 测试验证完整用户工作流真实或模拟 API 调用集成测试验证 SDK 与后端 API 之间的机制契约事件类型、事件顺序、流式分块、连接检测单元测试则纯本地、无外部依赖地验证工具类本身。测试脚本定义在 sdk/package.json 中四个核心命令分别为命令实际执行内容test:e2ebun test e2e/streaming/ e2e/workflows/ e2e/custom-agents/ e2e/features/test:integrationbun test e2e/integration/test:unit:e2e通过test:files汇总src与e2e/utils下的*.test.ts排除*.integration.test.tstestbun test $(bun run --silent test:files)从脚本可以看出E2E 与集成测试全部基于 Bun 的测试运行器bun:test这也是所有测试文件统一使用import { describe, test, expect, beforeAll } from bun:test的原因。二、前置条件环境变量与 Mock 模式根据 sdk/e2e/README.md 与 sdk/e2e/utils/get-api-key.ts运行测试需要以下前置条件API KeyE2E 与集成测试需要设置CODEBUFF_API_KEY环境变量Opt-in 开关本地进行真实 API 调用需设置RUN_CODEBUFF_E2EtrueCI 环境默认自动执行优雅跳过文档说明未设置 API Key 时测试会优雅跳过。深入源码会发现一套更有意思的实现机制getApiKey()并不是简单地抛错或跳过而是区分两种模式// sdk/e2e/utils/get-api-key.ts要点 const shouldRunLiveE2e process.env.RUN_CODEBUFF_E2E true export function getApiKey(): string { if (shouldRunLiveE2e) { const apiKey process.env.CODEBUFF_API_KEY if (!apiKey) { throw new Error(CODEBUFF_API_KEY environment variable is required for live e2e tests. ...) } return apiKey } setupE2eMocks() // 注入全部 Mock process.env.CODEBUFF_API_KEY E2E_MOCK_API_KEY return E2E_MOCK_API_KEY // codebuff-e2e-mock }也就是说未设置RUN_CODEBUFF_E2Etrue时测试并不会真的打到线上而是自动进入 Mock 模式注入一个固定的模拟 Keycodebuff-e2e-mock保证测试在本地可确定性运行。skipIfNoApiKey()的实现恒返回false因此所有测试用例始终执行只是底层从真实调用切换为模拟调用。Mock 机制底层实现Mock 的核心实现在 sdk/e2e/utils/e2e-mocks.ts它使用 Bun 测试运行器内置的spyOn对 SDK 的数据库层与 LLM 层进行替换数据库模块sdk/src/impl/database替换getUserInfoFromApiKey、fetchAgentFromDatabase、startAgentRun、finishAgentRun、addAgentStep其中 Agent 模板由buildMockAgentTemplate按publisherId/agentIdversion的 ID 格式动态构造LLM 模块sdk/src/impl/llm替换promptAiSdkStream、promptAiSdk、promptAiSdkStructured模拟流式输出与结构化输出连接检测将CodebuffClient.prototype.checkConnection直接 Mock 为恒返回true。模拟 LLM 层还内置了一套关键词响应路由buildMockResponseText例如提示词包含weather会返回The weather is sunny, temperature 72F.包含favorite number is会返回Got it.包含2 2会返回4。工具调用则由buildMockToolCall按提示词关键词自动选择get_weather、execute_sql、apply_patch、fetch_api等工具并生成输入。这正是多轮对话、天气 Agent 等 E2E 测试能够在本地稳定断言的根基。错误识别辅助sdk/e2e/utils/get-api-key.ts 还提供两个断言辅助函数isAuthError(output)当输出类型为error且消息包含authentication、api key或unauthorized时判定为鉴权错误isNetworkError(output)当状态码为 408超时、429限流或 5xx或消息包含network error时判定为网络错误。二者共同帮助测试区分鉴权失败与网络抖动在 CI 中便于对偶发错误做降级处理。三、E2E 测试详解test:e2eE2E 测试通过bun run test:e2e运行覆盖四类场景对应四个子目录目录覆盖场景对应测试文件streaming/子 Agent 流式输出、并发流隔离subagent-streaming.e2e.test.ts、concurrent-streams.e2e.test.tsworkflows/多轮对话、错误恢复multi-turn-conversation.e2e.test.ts、error-recovery.e2e.test.tscustom-agents/自定义 Agent 自定义工具weather-agent.e2e.test.ts、database-query-agent.e2e.test.ts、api-integration-agent.e2e.test.ts、apply-patch-tool.e2e.test.tsfeatures/projectFiles、knowledgeFiles、maxAgentStepsproject-files.e2e.test.ts、knowledge-files.e2e.test.ts、max-agent-steps.e2e.test.ts3.1 流式行为子 Agent 流与并发流子 Agent 流测试subagent-streaming.e2e.test.ts验证嵌套子 Agent 的事件流与父子关系核心断言包括subagent_start与subagent_finish事件按agentId成对出现subagent_start事件的agentId、agentType、displayName均为字符串onlyChild为布尔值parentAgentId与prompt为可选的同类型字段子 Agent 的文本块通过handleStreamChunk以subagent_chunk结构转发包含agentId、agentType、chunk字段同一agentId不应出现重复的subagent_start事件。测试中使用的 Agent 是codebuff/baselatest其特点是会在执行中派生文件选择、代码搜索等子 Agent从而天然触发上述事件。并发流测试concurrent-streams.e2e.test.ts则验证多个并发client.run()之间的事件流互不干扰为每个 run 单独创建EventCollector通过Promise.all同时发起 2~3 个 run断言每个收集器都有独立的start/finish事件、独立的streamChunks且错误列表为空。该测试在工程上很有价值——它证明了 SDK 客户端在多 run 场景下的流隔离能力。3.2 多轮对话previousRun链式续聊多轮对话测试multi-turn-conversation.e2e.test.ts验证previousRun机制第一次 run 返回的RunState作为下一次run()的previousRun传入从而保持上下文。测试用三段式对话验证记忆保持先让 Agent 记住最喜欢的数字是 42第二轮问我告诉你的最喜欢的数字是什么断言collector2.getFullText()中包含42随后用 todo app 场景做三连击第三轮断言回复中包含todo或task。从源码看previousRun正是 sdk/src/run.ts 中RunOptions的字段其注释明确指出传入上一次run()返回的 JSON 状态即可延续会话上下文。3.3 错误恢复与中止错误恢复测试error-recovery.e2e.test.ts覆盖四种异常场景空 prompt不应崩溃至少产生start事件不存在的 Agentnonexistent-agent-that-does-not-exist-12345输出要么是带message的error要么被优雅处理特殊字符 promptemoji、引号、反引号、换行混排的 prompt 应正常完成并产生finishAbortController 中止signal: abortController.signal在 500ms 后中止长任务断言结果为 error 或已有部分事件。其中signal参数在 sdk/src/run.ts 的RunOptions中有明确定义说明 SDK 原生支持AbortSignal取消机制。3.4 自定义 Agent 与自定义工具自定义 Agent 测试演示了 SDK 最强大的扩展能力通过agentDefinitions与customToolDefinitions注入自定义 Agent 和工具。以天气 Agentweather-agent.e2e.test.ts为例const weatherAgent: AgentDefinition { id: weather-agent, model: anthropic/claude-sonnet-4.5, displayName: Weather Agent, toolNames: [get_weather], instructionsPrompt: You are a helpful weather assistant. When asked about weather, use the get_weather tool to fetch current conditions., } const weatherTool getCustomToolDefinition({ toolName: get_weather, description: Get current weather for a city, inputSchema: z.object({ city: z.string().describe(Name of the city) }), exampleInputs: [{ city: New York }], execute: async ({ city }) { const weather MOCK_WEATHER_DATA[city] || { temp: 65, condition: Unknown } return [{ type: json, value: { city, temperature: weather.temp, condition: weather.condition } }] }, })随后通过client.run({ agent: weather-agent, agentDefinitions: [weatherAgent], customToolDefinitions: [weatherTool], ... })执行断言产生了tool_call事件toolName get_weather且回复包含天气相关信息。这里的getCustomToolDefinition实现在 sdk/src/custom-tool.ts其参数含义如下参数类型说明toolNamestring工具名称若与内置工具同名会得到类型层面的报错提示要求改用overrideToolsinputSchemaz.ZodTypeZod 4 输入校验 schemaLLM 调用工具时按此校验参数descriptionstring传给 LLM 的工具描述说明工具做什么、何时使用endsAgentStepboolean默认true表示该工具调用会作为一步的终止序列LLM 必须等待工具结果后才能继续调用其他工具exampleInputsInput[]示例输入用于帮助 LLM 理解调用格式execute(params) PromiseToolResultOutput[]工具执行体返回ToolResultOutput数组如{ type: json, value }配套的数据库查询 Agentdatabase-query-agent.e2e.test.ts展示了execute_sql工具与MOCK_DATABASE夹具users 表含 Alice/Bob/Charlie的组合用法并实现了简单的 WHERE 子句解析API 集成 Agentapi-integration-agent.e2e.test.ts展示了fetch_api工具对jsonplaceholder/example域名返回 Mock 数据、对其他 URL 走真实 fetch带 5 秒 AbortController 超时apply_patch 测试apply-patch-tool.e2e.test.ts则在临时目录中真实执行文件补丁并回读验证文件内容。3.5 SDK 特性覆盖projectFilesproject-files.e2e.test.ts将项目文件以{ src/index.ts: ... }形式注入Agent 可据此列出文件、分析内容。夹具定义在 sdk/e2e/utils/test-fixtures.ts 的SAMPLE_PROJECT_FILES中knowledgeFilesknowledge-files.e2e.test.ts注入知识文件Agent 能从中读取秘密暗号PINEAPPLE42或公司价值观Innovation / Integrity。与projectFiles的区别在 sdk/src/client.ts 的注释中有明确说明knowledgeFiles会直接加入 Agent 上下文而projectFiles用于帮助 Codebuff 挑选合适的源码文件作为上下文maxAgentStepsmax-agent-steps.e2e.test.ts限制 Agent 最大执行步数如 5、2作为防止 Agent 失控的安全阀。sdk/src/client.ts 的文档注释建议一个合理的默认值约为 20。四、集成测试详解test:integration集成测试通过bun run test:integration运行聚焦 SDK 与 API 的机制层契约目录为sdk/e2e/integration/测试文件验证内容event-types.integration.test.ts验证所有PrintModeEvent类型均被正确发射event-ordering.integration.test.ts验证事件顺序start → content → finishstream-chunks.integration.test.ts验证handleStreamChunk回调connection-check.integration.test.ts验证checkConnection()方法4.1 事件类型契约事件类型测试断言了PrintModeEvent的核心结构类型定义见 common/src/types/print-mode.tsstartrun 开始时发射携带messageHistoryLengthnumberfinishrun 结束时发射携带totalCostnumber非负text响应生成过程中的文本事件多个text事件拼接即为完整回复tool_call/tool_result工具调用时成对出现分别携带toolCallId、toolName、input与toolCallId、toolName、output此外还有error、subagent_start、subagent_finish、reasoning_delta、download等类型。完整的PrintModeEvent判别联合discriminated union由 Zod 的printModeEventSchema定义SDK 在 sdk/src/index.ts 中将其作为公共类型导出。4.2 事件顺序契约事件顺序测试event-ordering.integration.test.ts是流式渲染正确性的基石验证了五条规则start事件必须是第一个事件findIndex结果为 0finish事件必须晚于所有text事件同一toolCallId的tool_result必须晚于其tool_call标准流程start → text → finish可用collector.verifyEventOrder([start, finish])验证最后一个finish之后不允许再出现任何非 finish 事件。这些断言直接支撑了 UI 层先渲染开始状态、流式追加文本、最终收尾的渲染逻辑。4.3 流式分块契约流式分块测试stream-chunks.integration.test.ts验证handleStreamChunk的三种块类型字符串块文本流式输出多个块拼接成完整文本subagent_chunk子 Agent 的文本块含agentId、agentType、chunkreasoning_chunk推理过程块含agentId、ancestorRunIds、chunk类型定义同样在 sdk/src/run.ts 的CodebuffClientOptions中。测试还验证了块是增量到达的记录每个块到达时间戳长响应应有多个块以及空 prompt、超长响应、特殊字符emoji、引号、换行、制表符场景下的流式健壮性。4.4 连接检测连接检测测试connection-check.integration.test.ts验证checkConnection()在后台可达时返回true且返回值为布尔类型。其实现位于 sdk/src/client.ts通过请求/api/healthz并校验status ok实现带 5 秒超时BYOK 模式下则改为探测 OpenRouter 的key或models端点。五、单元测试EventCollectortest:unit:e2e单元测试目录为sdk/e2e/utils/__tests__/目前包含 event-collector.test.ts纯本地运行、无任何外部依赖。测试覆盖EventCollector的全部 APIhandleEvent按序收集事件并单独追踪error事件handleStreamChunk收集字符串块与subagent_chunkgetEventsByType/hasEventType/getFirstEvent/getLastEvent按类型查询、判断、取首取尾getFullText/getFullStreamText拼接全部文本事件 / 拼接字符串流块getSubagentChunks(agentId)按 Agent 过滤子 Agent 流块verifyEventOrder按期望顺序校验事件出现次序支持部分顺序getUniqueEventTypes/countEvents/clear/getSummary去重、计数、清空与调试摘要。EventCollector本身实现在 sdk/e2e/utils/event-collector.ts是整个测试套件的断言中枢——几乎所有 E2E 与集成测试都通过它收集事件再断言。其StreamChunk类型string | subagent_chunk | reasoning_chunk与 sdk/src/run.ts 中的回调签名完全对齐。六、可运行示例开箱即用的 SDK 用法examples/目录包含 6 个可运行脚本非测试覆盖了 SDK 最常见的六类工程场景。运行方式为bun run sdk/e2e/examples/code-reviewer.example.ts示例功能描述关键点code-reviewer.example.tsAI 代码审查提交含除零 Bug 的divide函数让 Agent 找出问题code-explainer.example.ts用通俗语言解释代码针对fetchUserData异步函数commit-message-generator.example.ts根据 diff 生成提交信息传入 git diff 文本sdk-lint.example.tsAI 驱动的 Linter让 Agent 以 linter 身份给出具体反馈sdk-refactor.example.ts代码重构要求使用现代 JavaScript 特性重写sdk-test-gen.example.ts单元测试生成要求生成 Jest 测试所有示例的结构高度一致是最佳实践模板读取CODEBUFF_API_KEY环境变量缺失即报错退出构造new CodebuffClient({ apiKey })调用client.run({ agent: codebuff/base2latest, prompt, handleStreamChunk })通过handleStreamChunk将字符串块实时写入process.stdout实现流式打印检查result.output.type error处理失败。其中handleStreamChunk只对typeof chunk string的块做输出、忽略subagent_chunk等结构化块是流式 UI 的极简范例。七、标准测试编写模式sdk/e2e/README.md 给出了两类官方推荐的测试模板可直接复用。7.1 E2E 测试模板import { describe, test, expect, beforeAll } from bun:test import { CodebuffClient } from ../../src/client import { EventCollector, getApiKey, skipIfNoApiKey, isAuthError, DEFAULT_AGENT, DEFAULT_TIMEOUT } from ../utils describe(E2E: My Test, () { let client: CodebuffClient beforeAll(() { if (skipIfNoApiKey()) return client new CodebuffClient({ apiKey: getApiKey() }) }) test(does something, async () { if (skipIfNoApiKey()) return const collector new EventCollector() const result await client.run({ agent: DEFAULT_AGENT, prompt: Test prompt, handleEvent: collector.handleEvent, }) if (isAuthError(result.output)) return expect(result.output.type).not.toBe(error) }, DEFAULT_TIMEOUT) })模板要素拆解beforeAllskipIfNoApiKey()集中初始化客户端保持用例简洁getApiKey()自动处理真实 Key 与 Mock Key 的切换EventCollector统一收集事件用于断言isAuthError(result.output)鉴权错误时直接返回避免 CI 误报DEFAULT_TIMEOUT超时上限为 120 秒2 分钟定义于 sdk/e2e/utils/test-fixtures.ts复杂场景如子 Agent 流会翻倍使用DEFAULT_TIMEOUT * 2DEFAULT_AGENT默认 Agent 为base2。7.2 单元测试模板import { describe, test, expect, beforeEach } from bun:test import { EventCollector } from ../event-collector describe(Unit: EventCollector, () { let collector: EventCollector beforeEach(() { collector new EventCollector() }) test(collects events, () { collector.handleEvent({ type: start, messageHistoryLength: 0 }) expect(collector.events).toHaveLength(1) }) })单元测试无需 API Key、无网络请求beforeEach中重建被测对象以保证用例隔离。八、测试数据夹具一览sdk/e2e/utils/test-fixtures.ts 提供了全套可复用测试数据SAMPLE_CODE六段示例代码简单函数、含 Bug 的除法、含 Bug 的类、异步函数、React 组件等SAMPLE_DIFFS单文件与多文件的 git diff 样本供 commit message、代码审查类测试使用SAMPLE_PROJECT_FILES模拟项目文件树src/index.ts、src/calculator.ts、package.json、README.md用于projectFiles注入测试MOCK_WEATHER_DATA/MOCK_DATABASE天气城市数据与用户表数据供自定义工具测试使用TEST_PROMPTS按场景命名的常用提示词集合DEFAULT_AGENT/DEFAULT_TIMEOUT默认 Agentbase2与默认超时120 秒。九、从测试看 SDK 核心 API最后从测试反观 SDK 的核心 API 面帮助理解测试为什么这样写CodebuffClientsdk/src/client.ts构造函数要求apiKey也可从CODEBUFF_API_KEY环境变量自动读取核心方法为run(options)与checkConnection()RunOptionssdk/src/run.ts除agent、prompt外支持previousRun多轮续聊、content多模态文本图片、signalAbortSignal 中止、params自定义 Agent 的结构化输入、extraToolResults、drainSteeringMessages运行中注入消息等高级能力CodebuffClientOptionssdk/src/run.tsprojectFiles、knowledgeFiles、agentDefinitions、customToolDefinitions、maxAgentSteps、handleEvent、handleStreamChunk、overrideTools替换内置工具实现、terminalCommandBroker等均可作为客户端级或单次 run 级配置传入。测试中常用的agent标识符格式为publisher/agentIdversion如codebuff/baselatest、codebuff/base2latest也可直接传AgentDefinition对象这在前述自定义 Agent 测试中已有充分演示。十、总结一套可本地运行、可 CI 验证、可上手复刻的测试体系sdk/e2e测试体系最值得借鉴的设计在于三点Mock 与真实调用的无缝切换通过RUN_CODEBUFF_E2E环境变量决定走 Mock本地确定性运行还是真实 APICI 全链路验证getApiKey()与setupE2eMocks()让测试代码本身无需任何分支统一的断言中枢EventCollector收敛了事件收集、类型过滤、顺序校验、文本拼接等全部断言能力使测试用例极度精简从机制到行为的全覆盖集成测试锁死事件类型与顺序契约E2E 测试验证多轮对话、并发流、子 Agent 流、自定义工具等真实工作流示例脚本则成为 SDK 使用者的上手教材。如果你正准备为 Codebuff SDK 编写集成测试建议直接从 sdk/e2e/utils/event-collector.ts 与 sdk/e2e/utils/get-api-key.ts 这两个工具类入手再参照 event-ordering.integration.test.ts 与 weather-agent.e2e.test.ts 的模板搭建自己的用例——这套分层清晰、可复用的测试结构值得每个接入 SDK 的项目直接借鉴。【免费下载链接】freebuffThe free coding agent项目地址: https://gitcode.com/GitHub_Trending/cod/freebuff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考