claude-code/docs/test-plans/14-integration-tests.md
2026-04-02 14:14:35 +08:00

5.9 KiB
Raw Permalink Blame History

Plan 14 — 集成测试搭建

优先级:中 | 新建 ~3 个测试文件 | 预估 ~30 个测试用例

当前 tests/integration/ 目录为空spec 设计的三个集成测试均未创建。本计划搭建 mock 基础设施并实现核心集成测试。


14.1 搭建 tests/mocks/ 基础设施

文件结构

tests/
├── mocks/
│   ├── api-responses.ts       # Claude API mock 响应
│   ├── file-system.ts         # 临时文件系统工具
│   └── fixtures/
│       ├── sample-claudemd.md # CLAUDE.md 样本
│       └── sample-messages.json # 消息样本
├── integration/
│   ├── tool-chain.test.ts
│   ├── context-build.test.ts
│   └── message-pipeline.test.ts
└── helpers/
    └── setup.ts               # 共享 beforeAll/afterAll

tests/mocks/file-system.ts

import { mkdtemp, rm, writeFile, mkdir } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

export async function createTempDir(prefix = "claude-test-"): Promise<string> {
  const dir = await mkdtemp(join(tmpdir(), prefix));
  return dir;
}

export async function cleanupTempDir(dir: string): Promise<void> {
  await rm(dir, { recursive: true, force: true });
}

export async function writeTempFile(dir: string, name: string, content: string): Promise<string> {
  const path = join(dir, name);
  await writeFile(path, content, "utf-8");
  return path;
}

tests/mocks/fixtures/sample-claudemd.md

# Project Instructions

This is a sample CLAUDE.md file for testing.

tests/mocks/api-responses.ts

export const mockStreamResponse = {
  type: "message_start" as const,
  message: {
    id: "msg_mock_001",
    type: "message" as const,
    role: "assistant",
    content: [],
    model: "claude-sonnet-4-20250514",
    stop_reason: null,
    stop_sequence: null,
    usage: { input_tokens: 100, output_tokens: 0 },
  },
};

export const mockTextBlock = {
  type: "content_block_start" as const,
  index: 0,
  content_block: { type: "text" as const, text: "Mock response" },
};

export const mockToolUseBlock = {
  type: "content_block_start" as const,
  index: 1,
  content_block: {
    type: "tool_use" as const,
    id: "toolu_mock_001",
    name: "Read",
    input: { file_path: "/tmp/test.txt" },
  },
};

export const mockEndEvent = {
  type: "message_stop" as const,
};

14.2 tests/integration/tool-chain.test.ts

目标:验证 Tool 注册 → 发现 → 权限检查链路。

前置条件

src/tools.tsgetAllBaseTools / getTools 导入链过重。策略:

  • 尝试直接 import 并 mock 最重依赖
  • 若不可行,改为测试 src/Tool.tsfindToolByName + 手动构造 tool 列表

用例

# 用例 验证点
1 findToolByName("Bash") 在已注册列表中查找 返回正确的 tool 定义
2 findToolByName("NonExistent") 返回 undefined
3 findToolByName 大小写不敏感 "bash" 也能找到
4 filterToolsByDenyRules 拒绝特定工具 被拒绝工具不在结果中
5 parseToolPreset("default") 返回已知列表 包含核心 tools
6 buildTool 构建的 tool 可被 findToolByName 发现 端到端验证

如果 getAllBaseTools 确实不可导入,改用 mock tool list 替代。


14.3 tests/integration/context-build.test.ts

目标验证系统提示组装流程CLAUDE.md 加载 + git status + 日期注入)。

前置条件

src/context.ts 依赖链极重。策略:

  • Mock src/bootstrap/state.ts(提供 cwd、projectRoot
  • Mock src/utils/git.ts(提供 git status
  • 使用真实 src/utils/claudemd.ts + 临时文件

用例

# 用例 验证点
1 基本 context 构建 返回值包含系统提示字符串
2 CLAUDE.md 内容出现在 context 中 stripHtmlComments 后的内容被包含
3 多层目录 CLAUDE.md 合并 父目录 + 子目录 CLAUDE.md 都被加载
4 无 CLAUDE.md 时不报错 context 正常返回,无 crash
5 git status 为 null context 正常构建(测试环境中 git 不可用时)

风险评估:如果 mock context.ts 的依赖链成本过高,退化为测试 buildEffectiveSystemPrompt(已在 systemPrompt.test.ts 中完成),记录为已知限制。


14.4 tests/integration/message-pipeline.test.ts

目标:验证用户输入 → 消息格式化 → API 请求构建。

前置条件

src/services/api/claude.ts 构建最终 API 请求。策略:

  • Mock Anthropic SDK 的 streaming endpoint
  • 验证请求参数结构

用例

# 用例 验证点
1 文本消息格式化 createUserMessage 生成正确 role+content
2 tool_result 消息格式化 包含 tool_use_id 和 content
3 多轮消息序列化 messages 数组保持顺序
4 系统提示注入到请求 API 请求的 system 字段非空
5 消息 normalize 后格式一致 normalizeMessages 输出结构正确

现实评估:消息格式化的大部分已在 messages.test.ts 覆盖。API 请求构建需要 mock SDK复杂度高。如果投入产出比低仅实现用例 1-3 和 5用例 4 标记为 stretch goal。


实施步骤

  1. 创建 tests/mocks/ 目录和基础文件
  2. 实现 tool-chain.test.ts(最低风险,最高价值)
  3. 评估 context-build.test.ts 可行性,决定是否实施
  4. 实现 message-pipeline.test.ts(可降级为单元测试)
  5. 更新 testing-spec.md 状态

验收标准

  • tests/mocks/ 基础设施可用
  • 至少 tool-chain.test.ts 实现并通过
  • 集成测试独立于单元测试运行:bun test tests/integration/
  • 所有集成测试使用 createTempDir + cleanupTempDir,不留文件系统残留
  • bun test 全部通过