|
|
@@ -1,455 +1,256 @@
|
|
|
# Testing Specification
|
|
|
|
|
|
-本文档定义了 claude-code 项目的测试规范,作为编写和维护测试代码的统一标准。
|
|
|
+本文档定义 claude-code 项目的测试规范、当前覆盖状态和改进计划。
|
|
|
|
|
|
-## 1. 测试目标
|
|
|
+## 1. 技术栈
|
|
|
|
|
|
-| 目标 | 说明 |
|
|
|
-|------|------|
|
|
|
-| **防止回归** | 确保已有功能不被新改动破坏,每次 PR 必须通过全部测试 |
|
|
|
-| **验证核心流程** | 覆盖 CLI 核心交互流程:Tool 调用链、Context 构建、消息处理 |
|
|
|
-| **文档化行为** | 通过测试用例记录各模块的预期行为,作为活文档供开发者参考 |
|
|
|
-
|
|
|
-## 2. 技术栈
|
|
|
-
|
|
|
-| 项 | 选型 | 说明 |
|
|
|
-|----|------|------|
|
|
|
-| 测试框架 | `bun:test` | Bun 内置,零配置,与运行时一致 |
|
|
|
-| 断言库 | `bun:test` 内置 `expect` | 兼容 Jest `expect` API |
|
|
|
-| Mock | `bun:test` 内置 `mock`/`spyOn` | 配合手动 mock fixtures |
|
|
|
-| 覆盖率 | `bun test --coverage` | 内置覆盖率报告 |
|
|
|
+| 项 | 选型 |
|
|
|
+|----|------|
|
|
|
+| 测试框架 | `bun:test` |
|
|
|
+| 断言/Mock | `bun:test` 内置 |
|
|
|
+| 覆盖率 | `bun test --coverage` |
|
|
|
+| CI | GitHub Actions,push/PR 到 main 自动运行 |
|
|
|
|
|
|
-## 3. 测试层次
|
|
|
+## 2. 测试层次
|
|
|
|
|
|
本项目采用 **单元测试 + 集成测试** 两层结构,不做 E2E 或快照测试。
|
|
|
|
|
|
-### 3.1 单元测试
|
|
|
-
|
|
|
-- **对象**:纯函数、工具类、解析器、独立模块
|
|
|
-- **特征**:无外部依赖、执行快、可并行
|
|
|
-- **示例场景**:
|
|
|
- - `src/utils/array.ts` — 数组操作函数
|
|
|
- - `src/utils/path.ts` — 路径解析
|
|
|
- - `src/utils/diff.ts` — diff 算法
|
|
|
- - `src/utils/permissions/` — 权限判断逻辑
|
|
|
- - `src/utils/model/` — 模型选择与 provider 路由
|
|
|
- - Tool 的 `inputSchema` 校验逻辑
|
|
|
-
|
|
|
-### 3.2 集成测试
|
|
|
-
|
|
|
-- **对象**:多模块协作流程
|
|
|
-- **特征**:可能需要 mock 外部服务(API、文件系统),测试模块间协作
|
|
|
-- **示例场景**:
|
|
|
- - Tool 调用链:`tools.ts` 注册 → `findToolByName` → tool `call()` 执行
|
|
|
- - Context 构建:`context.ts` 组装系统提示(CLAUDE.md 加载 + git status + 日期)
|
|
|
- - 消息处理管线:用户输入 → 消息格式化 → API 请求构建
|
|
|
-
|
|
|
-## 4. 文件结构
|
|
|
+- **单元测试** — 纯函数、工具类、解析器。文件就近放置于 `src/**/__tests__/`。
|
|
|
+- **集成测试** — 多模块协作流程。集中于 `tests/integration/`。
|
|
|
|
|
|
-采用 **混合模式**:单元测试就近放置,集成测试集中管理。
|
|
|
+## 3. 文件结构与命名
|
|
|
|
|
|
```
|
|
|
src/
|
|
|
-├── utils/
|
|
|
-│ ├── array.ts
|
|
|
-│ ├── __tests__/ # 单元测试:就近放置
|
|
|
-│ │ ├── array.test.ts
|
|
|
-│ │ ├── set.test.ts
|
|
|
-│ │ └── path.test.ts
|
|
|
-│ ├── model/
|
|
|
-│ │ ├── providers.ts
|
|
|
-│ │ └── __tests__/
|
|
|
-│ │ └── providers.test.ts
|
|
|
-│ └── permissions/
|
|
|
-│ ├── index.ts
|
|
|
-│ └── __tests__/
|
|
|
-│ └── permissions.test.ts
|
|
|
-├── tools/
|
|
|
-│ ├── BashTool/
|
|
|
-│ │ ├── index.ts
|
|
|
-│ │ └── __tests__/
|
|
|
-│ │ └── BashTool.test.ts
|
|
|
-│ └── FileEditTool/
|
|
|
-│ ├── index.ts
|
|
|
-│ └── __tests__/
|
|
|
-│ └── FileEditTool.test.ts
|
|
|
-tests/ # 集成测试:集中管理
|
|
|
-├── integration/
|
|
|
-│ ├── tool-chain.test.ts
|
|
|
-│ ├── context-build.test.ts
|
|
|
-│ └── message-pipeline.test.ts
|
|
|
-├── mocks/ # 通用 mock / fixtures
|
|
|
-│ ├── api-responses.ts # Claude API mock 响应
|
|
|
-│ ├── file-system.ts # 文件系统 mock 工具
|
|
|
-│ └── fixtures/
|
|
|
-│ ├── sample-claudemd.md
|
|
|
-│ └── sample-messages.json
|
|
|
-└── helpers/ # 测试辅助函数
|
|
|
- └── setup.ts
|
|
|
+├── utils/__tests__/ # 纯函数单元测试
|
|
|
+├── tools/<Tool>/__tests__/ # Tool 单元测试
|
|
|
+├── services/mcp/__tests__/ # MCP 单元测试
|
|
|
+├── utils/permissions/__tests__/
|
|
|
+├── utils/model/__tests__/
|
|
|
+├── utils/settings/__tests__/
|
|
|
+├── utils/shell/__tests__/
|
|
|
+├── utils/git/__tests__/
|
|
|
+└── __tests__/ # 顶层模块测试 (Tool.ts, tools.ts)
|
|
|
+tests/
|
|
|
+├── integration/ # 集成测试(尚未创建)
|
|
|
+├── mocks/ # 共享 mock/fixture(尚未创建)
|
|
|
+└── helpers/ # 测试辅助函数
|
|
|
```
|
|
|
|
|
|
-### 命名规则
|
|
|
+- 测试文件:`<module>.test.ts`
|
|
|
+- 命名风格:`describe("functionName")` + `test("行为描述")`,英文
|
|
|
+- 编写原则:Arrange-Act-Assert、单一职责、独立性、边界覆盖
|
|
|
|
|
|
-| 项 | 规则 |
|
|
|
-|----|------|
|
|
|
-| 测试文件 | `<module-name>.test.ts` |
|
|
|
-| 测试目录 | `__tests__/`(单元)、`tests/integration/`(集成) |
|
|
|
-| Fixture 文件 | `tests/mocks/fixtures/` 下按用途命名 |
|
|
|
-| Helper 文件 | `tests/helpers/` 下按功能命名 |
|
|
|
-
|
|
|
-## 5. 命名与编写规范
|
|
|
-
|
|
|
-### 5.1 命名风格
|
|
|
-
|
|
|
-使用 `describe` + `it`/`test` 英文描述:
|
|
|
+## 4. 当前覆盖状态
|
|
|
|
|
|
-```typescript
|
|
|
-import { describe, expect, test } from "bun:test";
|
|
|
+> 更新日期:2026-04-02 | **1177 tests, 64 files, 0 fail, 837ms**
|
|
|
|
|
|
-describe("findToolByName", () => {
|
|
|
- test("returns the tool when name matches exactly", () => {
|
|
|
- // ...
|
|
|
- });
|
|
|
-
|
|
|
- test("returns undefined when no tool matches", () => {
|
|
|
- // ...
|
|
|
- });
|
|
|
-
|
|
|
- test("is case-insensitive for tool name lookup", () => {
|
|
|
- // ...
|
|
|
- });
|
|
|
-});
|
|
|
-```
|
|
|
+### 4.1 可靠度评分
|
|
|
|
|
|
-### 5.2 describe 块组织原则
|
|
|
+每个测试文件按断言深度、边界覆盖、mock 质量、测试独立性综合评定:
|
|
|
|
|
|
-- 顶层 `describe` 对应被测函数/类/模块名
|
|
|
-- 可嵌套 `describe` 对分支场景分组(如 `describe("when input is empty", ...)`)
|
|
|
-- 每个 `test` 应测试一个行为,命名采用 **"动作 + 预期结果"** 格式
|
|
|
-
|
|
|
-### 5.3 编写原则
|
|
|
-
|
|
|
-| 原则 | 说明 |
|
|
|
+| 等级 | 含义 |
|
|
|
|------|------|
|
|
|
-| **Arrange-Act-Assert** | 每个测试分三段:准备数据、执行操作、验证结果 |
|
|
|
-| **单一职责** | 一个 `test` 只验证一个行为 |
|
|
|
-| **独立性** | 测试之间无顺序依赖,无共享可变状态 |
|
|
|
-| **可读性优先** | 测试代码是文档,宁可重复也不过度抽象 |
|
|
|
-| **边界覆盖** | 空值、边界值、异常输入必须覆盖 |
|
|
|
-
|
|
|
-### 5.4 异步测试
|
|
|
-
|
|
|
-```typescript
|
|
|
-test("reads file content correctly", async () => {
|
|
|
- const content = await readFile("/tmp/test.txt");
|
|
|
- expect(content).toContain("expected");
|
|
|
-});
|
|
|
-```
|
|
|
-
|
|
|
-## 6. Mock 策略
|
|
|
-
|
|
|
-采用 **混合管理**:通用 mock 集中于 `tests/mocks/`,专用 mock 就近定义。
|
|
|
-
|
|
|
-### 6.1 Claude API Mock(集中管理)
|
|
|
-
|
|
|
-所有 API 测试全部使用 mock,不调用真实 API。
|
|
|
-
|
|
|
-```typescript
|
|
|
-// tests/mocks/api-responses.ts
|
|
|
-export const mockStreamResponse = {
|
|
|
- type: "message_start",
|
|
|
- message: {
|
|
|
- id: "msg_mock_001",
|
|
|
- type: "message",
|
|
|
- role: "assistant",
|
|
|
- content: [],
|
|
|
- model: "claude-sonnet-4-20250514",
|
|
|
- // ...
|
|
|
- },
|
|
|
-};
|
|
|
-
|
|
|
-export const mockToolUseResponse = {
|
|
|
- type: "content_block_start",
|
|
|
- content_block: {
|
|
|
- type: "tool_use",
|
|
|
- id: "toolu_mock_001",
|
|
|
- name: "Read",
|
|
|
- input: { file_path: "/tmp/test.txt" },
|
|
|
- },
|
|
|
-};
|
|
|
-```
|
|
|
-
|
|
|
-### 6.2 模块级 Mock(就近定义)
|
|
|
-
|
|
|
-```typescript
|
|
|
-import { mock } from "bun:test";
|
|
|
-
|
|
|
-// mock 整个模块
|
|
|
-mock.module("src/services/api/claude.ts", () => ({
|
|
|
- createApiClient: () => ({
|
|
|
- stream: mock(() => mockStreamResponse),
|
|
|
- }),
|
|
|
-}));
|
|
|
-```
|
|
|
-
|
|
|
-### 6.3 文件系统 Mock
|
|
|
-
|
|
|
-对于需要文件系统交互的测试,使用临时目录:
|
|
|
-
|
|
|
-```typescript
|
|
|
-import { mkdtemp, rm } from "node:fs/promises";
|
|
|
-import { tmpdir } from "node:os";
|
|
|
-import { join } from "node:path";
|
|
|
-import { afterAll, beforeAll } from "bun:test";
|
|
|
-
|
|
|
-let tempDir: string;
|
|
|
-
|
|
|
-beforeAll(async () => {
|
|
|
- tempDir = await mkdtemp(join(tmpdir(), "claude-test-"));
|
|
|
-});
|
|
|
-
|
|
|
-afterAll(async () => {
|
|
|
- await rm(tempDir, { recursive: true });
|
|
|
-});
|
|
|
-```
|
|
|
-
|
|
|
-## 7. 优先测试模块
|
|
|
-
|
|
|
-按优先级从高到低排列,括号内为目标覆盖率:
|
|
|
-
|
|
|
-### P0 — 核心(行覆盖率 >= 80%)
|
|
|
-
|
|
|
-| 模块 | 路径 | 测试重点 |
|
|
|
-|------|------|----------|
|
|
|
-| **Tool 系统** | `src/tools/`, `src/Tool.ts`, `src/tools.ts` | tool 注册/发现、inputSchema 校验、call() 执行与错误处理 |
|
|
|
-| **工具函数** | `src/utils/` 下纯函数 | 各种 utility 的正确性与边界情况 |
|
|
|
-| **Context 构建** | `src/context.ts`, `src/utils/claudemd.ts` | 系统提示拼装、CLAUDE.md 发现与加载、context 内容完整性 |
|
|
|
-
|
|
|
-### P1 — 重要(行覆盖率 >= 60%)
|
|
|
-
|
|
|
-| 模块 | 路径 | 测试重点 |
|
|
|
-|------|------|----------|
|
|
|
-| **权限系统** | `src/utils/permissions/` | 权限模式判断、tool 许可/拒绝逻辑 |
|
|
|
-| **模型路由** | `src/utils/model/` | provider 选择、模型名映射、fallback 逻辑 |
|
|
|
-| **消息处理** | `src/types/message.ts`, `src/utils/messages.ts` | 消息类型构造、格式化、过滤 |
|
|
|
-| **CLI 参数** | `src/main.tsx` 中的 Commander 配置 | 参数解析、模式切换(REPL/pipe) |
|
|
|
-
|
|
|
-### P2 — 补充
|
|
|
-
|
|
|
-| 模块 | 路径 | 测试重点 |
|
|
|
-|------|------|----------|
|
|
|
-| **Cron 调度** | `src/utils/cron*.ts` | cron 表达式解析、任务调度逻辑 |
|
|
|
-| **Git 工具** | `src/utils/git.ts` | git 命令构造、输出解析 |
|
|
|
-| **Config** | `src/utils/config.ts`, `src/utils/settings/` | 配置加载、合并、默认值 |
|
|
|
-
|
|
|
-## 8. 覆盖率要求
|
|
|
-
|
|
|
-| 范围 | 目标 | 说明 |
|
|
|
+| **GOOD** | 断言精确(exact match),边界充分,结构清晰 |
|
|
|
+| **ACCEPTABLE** | 正常路径覆盖完整,部分边界或断言可加强 |
|
|
|
+| **WEAK** | 存在明显缺陷:断言过弱、重要边界缺失、或有脆弱性风险 |
|
|
|
+
|
|
|
+### 4.2 按模块分布
|
|
|
+
|
|
|
+#### P0 — 核心模块
|
|
|
+
|
|
|
+| 文件 | Tests | 评分 | 覆盖范围 | 主要不足 |
|
|
|
+|------|-------|------|----------|----------|
|
|
|
+| `src/__tests__/Tool.test.ts` | 20 | GOOD | buildTool, toolMatchesName, findToolByName, filterToolProgressMessages | — |
|
|
|
+| `src/__tests__/tools.test.ts` | 9 | ACCEPTABLE | parseToolPreset, filterToolsByDenyRules | 预设覆盖仅测 "default";有冗余用例 |
|
|
|
+| `src/tools/FileEditTool/__tests__/utils.test.ts` | 22 | ACCEPTABLE | normalizeQuotes, applyEditToFile, preserveQuoteStyle | `findActualString` 断言过弱(`not.toBeNull`);`preserveQuoteStyle` 仅 2 用例 |
|
|
|
+| `src/tools/shared/__tests__/gitOperationTracking.test.ts` | 14 | WEAK | parseGitCommitId, detectGitOperation | **未 mock analytics 依赖**,测试产生副作用;6 个 GH PR action 仅测 2 个 |
|
|
|
+| `src/tools/BashTool/__tests__/destructiveCommandWarning.test.ts` | 21 | ACCEPTABLE | git/rm/SQL/k8s/terraform 危险模式 | safe commands 4 断言合一;缺少 `rm -rf /`、`DROP DATABASE`、管道命令 |
|
|
|
+| `src/tools/BashTool/__tests__/commandSemantics.test.ts` | 10 | ACCEPTABLE | grep/diff/test/rg/find 退出码语义 | mock `splitCommand_DEPRECATED` 与实现可能分歧;覆盖可更全面 |
|
|
|
+
|
|
|
+**Utils 纯函数(19 文件):**
|
|
|
+
|
|
|
+| 文件 | Tests | 评分 | 覆盖范围 | 主要不足 |
|
|
|
+|------|-------|------|----------|----------|
|
|
|
+| `utils/__tests__/array.test.ts` | 12 | GOOD | intersperse, count, uniq | — |
|
|
|
+| `utils/__tests__/set.test.ts` | 11 | GOOD | difference, intersects, every, union | — |
|
|
|
+| `utils/__tests__/xml.test.ts` | 9 | GOOD | escapeXml, escapeXmlAttr | 缺 null/undefined 输入测试 |
|
|
|
+| `utils/__tests__/hash.test.ts` | 12 | ACCEPTABLE | djb2Hash, hashContent, hashPair | `hashContent`/`hashPair` 无已知答案断言(仅测确定性) |
|
|
|
+| `utils/__tests__/stringUtils.test.ts` | 30 | GOOD | 10 个函数全覆盖,含 Unicode 边界 | — |
|
|
|
+| `utils/__tests__/semver.test.ts` | 16 | ACCEPTABLE | gt/gte/lt/lte/satisfies/order | 缺 pre-release、tilde range、畸形版本串 |
|
|
|
+| `utils/__tests__/uuid.test.ts` | 6 | ACCEPTABLE | validateUuid | 大写测试仅 `not.toBeNull`,未验证标准化输出 |
|
|
|
+| `utils/__tests__/format.test.ts` | 20 | WEAK | formatFileSize, formatDuration, formatNumber 等 | **多处 `toContain` 应为 `toBe`**:formatNumber/formatTokens/formatRelativeTime 仅检查子串 |
|
|
|
+| `utils/__tests__/frontmatterParser.test.ts` | 22 | GOOD | parseFrontmatter, splitPathInFrontmatter, parsePositiveIntFromFrontmatter | — |
|
|
|
+| `utils/__tests__/file.test.ts` | 13 | ACCEPTABLE | convertLeadingTabsToSpaces, addLineNumbers, stripLineNumberPrefix | `addLineNumbers` 仅 `toContain`;缺 Windows 路径分隔符测试 |
|
|
|
+| `utils/__tests__/glob.test.ts` | 6 | ACCEPTABLE | extractGlobBaseDirectory | 缺绝对路径、根 `/`、Windows 路径 |
|
|
|
+| `utils/__tests__/diff.test.ts` | 8 | ACCEPTABLE | adjustHunkLineNumbers, getPatchFromContents | `getPatchFromContents` 仅检查结构,未验证 diff 内容正确性 |
|
|
|
+| `utils/__tests__/json.test.ts` | 15 | GOOD | safeParseJSON, parseJSONL, addItemToJSONCArray | — |
|
|
|
+| `utils/__tests__/truncate.test.ts` | 18 | ACCEPTABLE | truncateToWidth, wrapText, truncatePathMiddle | **缺 CJK/emoji/wide-char 测试**(这是宽度感知实现的核心场景) |
|
|
|
+| `utils/__tests__/path.test.ts` | 15 | ACCEPTABLE | containsPathTraversal, normalizePathForConfigKey | 仅覆盖 2/5+ 导出函数 |
|
|
|
+| `utils/__tests__/tokens.test.ts` | 18 | GOOD | getTokenCountFromUsage, doesMostRecentAssistantMessageExceed200k 等 | — |
|
|
|
+
|
|
|
+**Context 构建(2 文件):**
|
|
|
+
|
|
|
+| 文件 | Tests | 评分 | 覆盖范围 | 主要不足 |
|
|
|
+|------|-------|------|----------|----------|
|
|
|
+| `utils/__tests__/claudemd.test.ts` | 14 | ACCEPTABLE | stripHtmlComments, isMemoryFilePath, getLargeMemoryFiles | **仅测 3 个辅助函数**,核心发现/加载/`@include` 指令/memoization 未覆盖 |
|
|
|
+| `utils/__tests__/systemPrompt.test.ts` | 8 | GOOD | buildEffectiveSystemPrompt | — |
|
|
|
+
|
|
|
+#### P1 — 重要模块
|
|
|
+
|
|
|
+| 文件 | Tests | 评分 | 覆盖范围 | 主要不足 |
|
|
|
+|------|-------|------|----------|----------|
|
|
|
+| `permissions/__tests__/permissionRuleParser.test.ts` | 16 | GOOD | escape/unescape 规则,roundtrip 完整性 | — |
|
|
|
+| `permissions/__tests__/permissions.test.ts` | 12 | ACCEPTABLE | getDenyRuleForTool, getAskRuleForTool, filterDeniedAgents | `as any` cast;缺 MCP tool deny 测试 |
|
|
|
+| `permissions/__tests__/shellRuleMatching.test.ts` | 19 | GOOD | 通配符、转义、正则特殊字符 | — |
|
|
|
+| `permissions/__tests__/PermissionMode.test.ts` | 18 | WEAK | permissionModeFromString, isExternalPermissionMode 等 | **`isExternalPermissionMode` false 路径从未执行**;mode 覆盖不完整(5 选 3) |
|
|
|
+| `permissions/__tests__/dangerousPatterns.test.ts` | 7 | WEAK | CROSS_PLATFORM_CODE_EXEC, DANGEROUS_BASH_PATTERNS | 纯数据 smoke test,无行为测试;不验证数组无重复 |
|
|
|
+| `model/__tests__/aliases.test.ts` | 15 | ACCEPTABLE | isModelAlias, isModelFamilyAlias | 缺 null/undefined/空串输入 |
|
|
|
+| `model/__tests__/model.test.ts` | 13 | ACCEPTABLE | firstPartyNameToCanonical | 缺空串、非标准日期后缀 |
|
|
|
+| `model/__tests__/providers.test.ts` | 9 | ACCEPTABLE | getAPIProvider, isFirstPartyAnthropicBaseUrl | `originalEnv` 声明未使用;env 恢复不完整 |
|
|
|
+| `utils/__tests__/messages.test.ts` | 36 | GOOD | createAssistantMessage, createUserMessage, extractTag 等 16 个 describe | `normalizeMessages` 仅检查长度未验证内容 |
|
|
|
+
|
|
|
+#### P2 — 补充模块
|
|
|
+
|
|
|
+| 文件 | Tests | 评分 | 覆盖范围 | 主要不足 |
|
|
|
+|------|-------|------|----------|----------|
|
|
|
+| `utils/__tests__/cron.test.ts` | 31 | GOOD | parseCronExpression, computeNextCronRun, cronToHuman | 缺月边界、闰年 |
|
|
|
+| `utils/__tests__/git.test.ts` | 15 | ACCEPTABLE | normalizeGitRemoteUrl (SSH/HTTPS/ssh://) | 缺 git://、file://、端口号 |
|
|
|
+| `settings/__tests__/config.test.ts` | 38 | GOOD | SettingsSchema, type guards, validateSettingsFileContent, formatZodError | 缺 DeniedMcpServerEntrySchema |
|
|
|
+
|
|
|
+#### P3-P6 — 扩展覆盖(27 文件)
|
|
|
+
|
|
|
+| 文件 | Tests | 评分 | 备注 |
|
|
|
+|------|-------|------|------|
|
|
|
+| `utils/__tests__/errors.test.ts` | 33 | GOOD | — |
|
|
|
+| `utils/__tests__/envUtils.test.ts` | 33 | GOOD | env 保存/恢复规范 |
|
|
|
+| `utils/__tests__/effort.test.ts` | 30 | GOOD | 5 个 mock 模块,边界完整 |
|
|
|
+| `utils/__tests__/argumentSubstitution.test.ts` | 22 | ACCEPTABLE | 缺转义引号、越界索引 |
|
|
|
+| `utils/__tests__/sanitization.test.ts` | 14 | ACCEPTABLE | — |
|
|
|
+| `utils/__tests__/sleep.test.ts` | 14 | GOOD | 时间相关测试,margin 充足 |
|
|
|
+| `utils/__tests__/CircularBuffer.test.ts` | 11 | ACCEPTABLE | 缺 capacity=1、空 buffer getRecent |
|
|
|
+| `utils/__tests__/memoize.test.ts` | 18 | GOOD | 缓存 hit/stale/LRU 全覆盖 |
|
|
|
+| `utils/__tests__/tokenBudget.test.ts` | 21 | GOOD | — |
|
|
|
+| `utils/__tests__/displayTags.test.ts` | 17 | GOOD | — |
|
|
|
+| `utils/__tests__/taggedId.test.ts` | 10 | GOOD | — |
|
|
|
+| `utils/__tests__/controlMessageCompat.test.ts` | 15 | GOOD | — |
|
|
|
+| `utils/__tests__/gitConfigParser.test.ts` | 21 | GOOD | — |
|
|
|
+| `utils/__tests__/windowsPaths.test.ts` | 19 | GOOD | 双向 round-trip 测试 |
|
|
|
+| `utils/__tests__/envExpansion.test.ts` | 15 | GOOD | — |
|
|
|
+| `utils/__tests__/formatBriefTimestamp.test.ts` | 10 | GOOD | 固定 now 时间戳,确定性 |
|
|
|
+| `utils/__tests__/notebook.test.ts` | 9 | ACCEPTABLE | 合并断言偏弱 |
|
|
|
+| `utils/__tests__/hyperlink.test.ts` | 10 | ACCEPTABLE | 空串测试行为注释混乱 |
|
|
|
+| `utils/__tests__/zodToJsonSchema.test.ts` | 9 | WEAK | **object 属性仅 `toBeDefined` 未验证类型**;optional 字段未验证 absence |
|
|
|
+| `utils/__tests__/objectGroupBy.test.ts` | 5 | ACCEPTABLE | 极简,缺 undefined key 测试 |
|
|
|
+| `utils/__tests__/contentArray.test.ts` | 6 | ACCEPTABLE | 缺混合 tool_result+text 交替 |
|
|
|
+| `utils/__tests__/slashCommandParsing.test.ts` | 8 | GOOD | — |
|
|
|
+| `utils/__tests__/groupToolUses.test.ts` | 10 | GOOD | — |
|
|
|
+| `utils/__tests__/shell/__tests__/outputLimits.test.ts` | 7 | ACCEPTABLE | — |
|
|
|
+| `utils/__tests__/envValidation.test.ts` | 9 | ACCEPTABLE | **可能存在 bug**:lower bound=100 但 value=1 报 valid |
|
|
|
+| `utils/git/__tests__/gitConfigParser.test.ts` | 20 | GOOD | — |
|
|
|
+| `services/mcp/__tests__/mcpStringUtils.test.ts` | 16 | GOOD | — |
|
|
|
+| `services/mcp/__tests__/normalization.test.ts` | 10 | GOOD | — |
|
|
|
+
|
|
|
+### 4.3 评分汇总
|
|
|
+
|
|
|
+| 等级 | 文件数 | 占比 |
|
|
|
+|------|--------|------|
|
|
|
+| **GOOD** | 30 | 47% |
|
|
|
+| **ACCEPTABLE** | 26 | 41% |
|
|
|
+| **WEAK** | 8 | 12% |
|
|
|
+
|
|
|
+## 5. 系统性问题
|
|
|
+
|
|
|
+### 5.1 断言过弱(Smell: `toContain` 代替精确匹配)
|
|
|
+
|
|
|
+以下文件的部分测试使用 `toContain` 或 `not.toBeNull` 检查结果,当实现返回包含目标子串的任何字符串时测试仍通过,无法检测格式错误:
|
|
|
+
|
|
|
+| 文件 | 受影响函数 | 建议 |
|
|
|
+|------|-----------|------|
|
|
|
+| `format.test.ts` | formatNumber, formatTokens, formatRelativeTime | 改为 `toBe` 精确匹配 |
|
|
|
+| `file.test.ts` | addLineNumbers | 断言完整输出格式 |
|
|
|
+| `diff.test.ts` | getPatchFromContents | 验证 hunk 内容正确性 |
|
|
|
+| `notebook.test.ts` | mapNotebookCellsToToolResult | 验证合并后内容 |
|
|
|
+| `uuid.test.ts` | validateUuid (uppercase) | 断言标准化后的精确值 |
|
|
|
+
|
|
|
+### 5.2 集成测试空白
|
|
|
+
|
|
|
+Spec 定义的三个集成测试均未创建:
|
|
|
+
|
|
|
+| 计划 | 状态 | 依赖 |
|
|
|
|------|------|------|
|
|
|
-| P0 核心模块 | **>= 80%** 行覆盖率 | Tool 系统、工具函数、Context 构建 |
|
|
|
-| P1 重要模块 | **>= 60%** 行覆盖率 | 权限、模型路由、消息处理 |
|
|
|
-| 整体 | 不设强制指标 | 逐步提升,不追求数字 |
|
|
|
-
|
|
|
-运行覆盖率报告:
|
|
|
-
|
|
|
-```bash
|
|
|
-bun test --coverage
|
|
|
-```
|
|
|
+| `tests/integration/tool-chain.test.ts` | 未创建 | 需 mock tools.ts 完整注册链 |
|
|
|
+| `tests/integration/context-build.test.ts` | 未创建 | 需 mock context.ts 重依赖链 |
|
|
|
+| `tests/integration/message-pipeline.test.ts` | 未创建 | 需 mock API 层 |
|
|
|
|
|
|
-## 9. CI 集成
|
|
|
+`tests/mocks/` 目录也不存在,无共享 mock/fixture 基础设施。
|
|
|
|
|
|
-已有 GitHub Actions 配置(`.github/workflows/ci.yml`),`bun test` 步骤已就位。
|
|
|
+### 5.3 Mock 相关
|
|
|
|
|
|
-### CI 中测试的运行条件
|
|
|
+| 问题 | 影响文件 | 说明 |
|
|
|
+|------|----------|------|
|
|
|
+| 未 mock 重依赖 | `gitOperationTracking.test.ts` | `detectGitOperation` 内部调用 analytics,测试产生副作用 |
|
|
|
+| `isExternalPermissionMode` 永远 true | `PermissionMode.test.ts` | false 路径从未被执行,测试形同虚设 |
|
|
|
+| env 恢复不完整 | `providers.test.ts` | 仅删除已知 key,新增 env var 会导致测试泄漏 |
|
|
|
|
|
|
-- **push** 到 `main` 或 `feature/*` 分支时自动运行
|
|
|
-- **pull_request** 到 `main` 分支时自动运行
|
|
|
-- 测试失败将阻止合并
|
|
|
+### 5.4 潜在 Bug
|
|
|
|
|
|
-### 本地运行
|
|
|
-
|
|
|
-```bash
|
|
|
-# 运行全部测试
|
|
|
-bun test
|
|
|
-
|
|
|
-# 运行特定文件
|
|
|
-bun test src/utils/__tests__/array.test.ts
|
|
|
-
|
|
|
-# 运行匹配模式
|
|
|
-bun test --filter "findToolByName"
|
|
|
-
|
|
|
-# 带覆盖率
|
|
|
-bun test --coverage
|
|
|
+| 文件 | 函数 | 问题 |
|
|
|
+|------|------|------|
|
|
|
+| `envValidation.test.ts` | validateBoundedIntEnvVar | 测试断言 lower bound=100 时 value=1 返回 `status: "valid"`,与函数名语义矛盾,可能是源码 bug 或测试逻辑错误 |
|
|
|
|
|
|
-# watch 模式(开发时)
|
|
|
-bun test --watch
|
|
|
-```
|
|
|
+### 5.5 已知限制
|
|
|
|
|
|
-## 10. 编写测试 Checklist
|
|
|
-
|
|
|
-每次新增或修改测试时,确认以下事项:
|
|
|
-
|
|
|
-- [ ] 测试文件位置正确(单元 → `__tests__/`,集成 → `tests/integration/`)
|
|
|
-- [ ] 命名遵循 `describe` + `test` 英文格式
|
|
|
-- [ ] 每个 test 只验证一个行为
|
|
|
-- [ ] 覆盖了正常路径、边界情况和错误情况
|
|
|
-- [ ] 无硬编码的绝对路径或系统特定值
|
|
|
-- [ ] Mock 使用得当(通用 → `tests/mocks/`,专用 → 就近)
|
|
|
-- [ ] 测试可独立运行,无顺序依赖
|
|
|
-- [ ] `bun test` 本地全部通过后再提交
|
|
|
-
|
|
|
-## 11. 当前测试覆盖状态
|
|
|
-
|
|
|
-> 更新日期:2026-04-02 | 总计:**1177 tests, 64 files, 0 failures**
|
|
|
-
|
|
|
-### P0 — 核心模块
|
|
|
-
|
|
|
-| 测试计划 | 测试文件 | 测试数 | 覆盖范围 |
|
|
|
-|----------|----------|--------|----------|
|
|
|
-| 01 - Tool 系统 | `src/__tests__/Tool.test.ts` | 25 | buildTool, toolMatchesName, findToolByName, getEmptyToolPermissionContext, filterToolProgressMessages |
|
|
|
-| | `src/__tests__/tools.test.ts` | 10 | parseToolPreset, filterToolsByDenyRules |
|
|
|
-| | `src/tools/shared/__tests__/gitOperationTracking.test.ts` | 16 | parseGitCommitId, detectGitOperation |
|
|
|
-| | `src/tools/FileEditTool/__tests__/utils.test.ts` | 24 | normalizeQuotes, stripTrailingWhitespace, findActualString, preserveQuoteStyle, applyEditToFile |
|
|
|
-| 02 - Utils 纯函数 | `src/utils/__tests__/array.test.ts` | 12 | intersperse, count, uniq |
|
|
|
-| | `src/utils/__tests__/set.test.ts` | 12 | difference, intersects, every, union |
|
|
|
-| | `src/utils/__tests__/xml.test.ts` | 9 | escapeXml, escapeXmlAttr |
|
|
|
-| | `src/utils/__tests__/hash.test.ts` | 12 | djb2Hash, hashContent, hashPair |
|
|
|
-| | `src/utils/__tests__/stringUtils.test.ts` | 35 | escapeRegExp, capitalize, plural, firstLineOf, countCharInString, normalizeFullWidthDigits/Space, safeJoinLines, EndTruncatingAccumulator, truncateToLines |
|
|
|
-| | `src/utils/__tests__/semver.test.ts` | 21 | gt, gte, lt, lte, satisfies, order |
|
|
|
-| | `src/utils/__tests__/uuid.test.ts` | 6 | validateUuid |
|
|
|
-| | `src/utils/__tests__/format.test.ts` | 24 | formatFileSize, formatSecondsShort, formatDuration, formatNumber, formatTokens, formatRelativeTime |
|
|
|
-| | `src/utils/__tests__/frontmatterParser.test.ts` | 28 | parseFrontmatter, splitPathInFrontmatter, parsePositiveIntFromFrontmatter, parseBooleanFrontmatter, parseShellFrontmatter |
|
|
|
-| | `src/utils/__tests__/file.test.ts` | 17 | convertLeadingTabsToSpaces, addLineNumbers, stripLineNumberPrefix, normalizePathForComparison, pathsEqual |
|
|
|
-| | `src/utils/__tests__/glob.test.ts` | 6 | extractGlobBaseDirectory |
|
|
|
-| | `src/utils/__tests__/diff.test.ts` | 8 | adjustHunkLineNumbers, getPatchFromContents |
|
|
|
-| | `src/utils/__tests__/json.test.ts` | 27 | safeParseJSON, safeParseJSONC, parseJSONL, addItemToJSONCArray (mock log.ts) |
|
|
|
-| | `src/utils/__tests__/truncate.test.ts` | 24 | truncateToWidth, truncateStartToWidth, truncateToWidthNoEllipsis, truncatePathMiddle, truncate, wrapText |
|
|
|
-| | `src/utils/__tests__/path.test.ts` | 15 | containsPathTraversal, normalizePathForConfigKey |
|
|
|
-| | `src/utils/__tests__/tokens.test.ts` | 22 | getTokenCountFromUsage, getTokenUsage, tokenCountFromLastAPIResponse, messageTokenCountFromLastAPIResponse, getCurrentUsage, doesMostRecentAssistantMessageExceed200k, getAssistantMessageContentLength (mock log.ts, tokenEstimation, slowOperations) |
|
|
|
-| 03 - Context 构建 | `src/utils/__tests__/claudemd.test.ts` | 16 | stripHtmlComments, isMemoryFilePath, getLargeMemoryFiles |
|
|
|
-| | `src/utils/__tests__/systemPrompt.test.ts` | 9 | buildEffectiveSystemPrompt |
|
|
|
-
|
|
|
-### P1 — 重要模块
|
|
|
-
|
|
|
-| 测试计划 | 测试文件 | 测试数 | 覆盖范围 |
|
|
|
-|----------|----------|--------|----------|
|
|
|
-| 04 - 权限系统 | `src/utils/permissions/__tests__/permissionRuleParser.test.ts` | 25 | escapeRuleContent, unescapeRuleContent, permissionRuleValueFromString, permissionRuleValueToString, normalizeLegacyToolName |
|
|
|
-| | `src/utils/permissions/__tests__/permissions.test.ts` | 13 | getDenyRuleForTool, getAskRuleForTool, getDenyRuleForAgent, filterDeniedAgents (mock log.ts, slowOperations) |
|
|
|
-| 05 - 模型路由 | `src/utils/model/__tests__/aliases.test.ts` | 16 | isModelAlias, isModelFamilyAlias |
|
|
|
-| | `src/utils/model/__tests__/model.test.ts` | 14 | firstPartyNameToCanonical |
|
|
|
-| | `src/utils/model/__tests__/providers.test.ts` | 10 | getAPIProvider, isFirstPartyAnthropicBaseUrl |
|
|
|
-| 06 - 消息处理 | `src/utils/__tests__/messages.test.ts` | 56 | createAssistantMessage, createUserMessage, isSyntheticMessage, getLastAssistantMessage, hasToolCallsInLastAssistantTurn, extractTag, isNotEmptyMessage, normalizeMessages, deriveUUID, isClassifierDenial 等 |
|
|
|
-
|
|
|
-### P2 — 补充模块
|
|
|
-
|
|
|
-| 测试计划 | 测试文件 | 测试数 | 覆盖范围 |
|
|
|
-|----------|----------|--------|----------|
|
|
|
-| 07 - Cron 调度 | `src/utils/__tests__/cron.test.ts` | 38 | parseCronExpression, computeNextCronRun, cronToHuman |
|
|
|
-| 08 - Git 工具 | `src/utils/__tests__/git.test.ts` | 18 | normalizeGitRemoteUrl (SSH/HTTPS/ssh:///代理URL/大小写规范化) |
|
|
|
-| 09 - 配置与设置 | `src/utils/settings/__tests__/config.test.ts` | 62 | SettingsSchema, PermissionsSchema, AllowedMcpServerEntrySchema, MCP 类型守卫, 设置常量函数, filterInvalidPermissionRules, validateSettingsFileContent, formatZodError |
|
|
|
-
|
|
|
-### P3 — Phase 1 纯函数扩展
|
|
|
-
|
|
|
-| 测试文件 | 测试数 | 覆盖范围 |
|
|
|
-|----------|--------|----------|
|
|
|
-| `src/utils/__tests__/errors.test.ts` | 28 | ClaudeError, AbortError, ConfigParseError, ShellError, TelemetrySafeError, isAbortError, hasExactErrorMessage, toError, errorMessage, getErrnoCode, isENOENT, getErrnoPath, shortErrorStack, isFsInaccessible, classifyAxiosError |
|
|
|
-| `src/utils/permissions/__tests__/shellRuleMatching.test.ts` | 22 | permissionRuleExtractPrefix, hasWildcards, matchWildcardPattern, parsePermissionRule, suggestionForExactCommand, suggestionForPrefix |
|
|
|
-| `src/utils/__tests__/argumentSubstitution.test.ts` | 18 | parseArguments, parseArgumentNames, generateProgressiveArgumentHint, substituteArguments |
|
|
|
-| `src/utils/__tests__/CircularBuffer.test.ts` | 12 | CircularBuffer class: add, addAll, getRecent, toArray, clear, length |
|
|
|
-| `src/utils/__tests__/sanitization.test.ts` | 14 | partiallySanitizeUnicode, recursivelySanitizeUnicode |
|
|
|
-| `src/utils/__tests__/slashCommandParsing.test.ts` | 8 | parseSlashCommand |
|
|
|
-| `src/utils/__tests__/contentArray.test.ts` | 6 | insertBlockAfterToolResults |
|
|
|
-| `src/utils/__tests__/objectGroupBy.test.ts` | 5 | objectGroupBy |
|
|
|
-
|
|
|
-### P4 — Phase 2 轻 Mock 扩展
|
|
|
-
|
|
|
-| 测试文件 | 测试数 | 覆盖范围 |
|
|
|
-|----------|--------|----------|
|
|
|
-| `src/utils/__tests__/envUtils.test.ts` | 34 | isEnvTruthy, isEnvDefinedFalsy, parseEnvVars, hasNodeOption, getAWSRegion, getDefaultVertexRegion, getVertexRegionForModel, isBareMode, shouldMaintainProjectWorkingDir, getClaudeConfigHomeDir |
|
|
|
-| `src/utils/__tests__/sleep.test.ts` | 14 | sleep (abort, throwOnAbort, abortError), withTimeout, sequential |
|
|
|
-| `src/utils/__tests__/memoize.test.ts` | 16 | memoizeWithTTL, memoizeWithTTLAsync (dedup/cache/clear), memoizeWithLRU (eviction/cache methods) |
|
|
|
-| `src/utils/__tests__/groupToolUses.test.ts` | 10 | applyGrouping (verbose, grouping, result collection, mixed messages) |
|
|
|
-| `src/utils/permissions/__tests__/dangerousPatterns.test.ts` | 7 | CROSS_PLATFORM_CODE_EXEC, DANGEROUS_BASH_PATTERNS 常量验证 |
|
|
|
-| `src/utils/shell/__tests__/outputLimits.test.ts` | 7 | getMaxOutputLength, BASH_MAX_OUTPUT_UPPER_LIMIT, BASH_MAX_OUTPUT_DEFAULT |
|
|
|
-
|
|
|
-### P5 — Phase 3 补全 + Phase 4 工具模块
|
|
|
-
|
|
|
-| 测试文件 | 测试数 | 覆盖范围 |
|
|
|
-|----------|--------|----------|
|
|
|
-| `src/utils/__tests__/zodToJsonSchema.test.ts` | 9 | zodToJsonSchema (string/number/object/enum/optional/array/boolean + caching) |
|
|
|
-| `src/utils/permissions/__tests__/PermissionMode.test.ts` | 19 | PERMISSION_MODES, permissionModeFromString, permissionModeTitle, permissionModeShortTitle, permissionModeSymbol, getModeColor, isDefaultMode, toExternalPermissionMode, isExternalPermissionMode |
|
|
|
-| `src/utils/__tests__/envValidation.test.ts` | 9 | validateBoundedIntEnvVar (default/valid/capped/invalid/boundary) |
|
|
|
-| `src/services/mcp/__tests__/mcpStringUtils.test.ts` | 18 | mcpInfoFromString, getMcpPrefix, buildMcpToolName, getMcpDisplayName, getToolNameForPermissionCheck, extractMcpToolDisplayName |
|
|
|
-| `src/tools/BashTool/__tests__/destructiveCommandWarning.test.ts` | 22 | getDestructiveCommandWarning (git/rm/database/infrastructure patterns) |
|
|
|
-| `src/tools/BashTool/__tests__/commandSemantics.test.ts` | 11 | interpretCommandResult (grep/diff/test/rg/find exit code semantics) |
|
|
|
-
|
|
|
-### P6 — Phase 5 扩展覆盖
|
|
|
-
|
|
|
-| 测试文件 | 测试数 | 覆盖范围 |
|
|
|
-|----------|--------|----------|
|
|
|
-| `src/utils/__tests__/tokenBudget.test.ts` | 20 | parseTokenBudget, findTokenBudgetPositions, getBudgetContinuationMessage |
|
|
|
-| `src/utils/__tests__/displayTags.test.ts` | 17 | stripDisplayTags, stripDisplayTagsAllowEmpty, stripIdeContextTags |
|
|
|
-| `src/utils/__tests__/taggedId.test.ts` | 10 | toTaggedId (prefix/uniqueness/format) |
|
|
|
-| `src/utils/__tests__/controlMessageCompat.test.ts` | 15 | normalizeControlMessageKeys (snake_case→camelCase 转换) |
|
|
|
-| `src/services/mcp/__tests__/normalization.test.ts` | 11 | normalizeNameForMCP (特殊字符/截断/空字符串/Unicode) |
|
|
|
-| `src/services/mcp/__tests__/envExpansion.test.ts` | 14 | expandEnvVarsInString ($VAR/${VAR}/嵌套/未定义/转义) |
|
|
|
-| `src/utils/git/__tests__/gitConfigParser.test.ts` | 20 | parseConfigString (key=value/section/subsection/多行/注释/引号) |
|
|
|
-| `src/utils/__tests__/formatBriefTimestamp.test.ts` | 10 | formatBriefTimestamp (秒/分/时/天/周/月/年) |
|
|
|
-| `src/utils/__tests__/hyperlink.test.ts` | 10 | createHyperlink (OSC 8 序列/file:///path/fallback) |
|
|
|
-| `src/utils/__tests__/windowsPaths.test.ts` | 20 | windowsPathToPosixPath, posixPathToWindowsPath (驱动器/UNC/相对路径) |
|
|
|
-| `src/utils/__tests__/notebook.test.ts` | 14 | parseCellId, mapNotebookCellsToToolResult (code/markdown/output) |
|
|
|
-| `src/utils/__tests__/effort.test.ts` | 38 | isEffortLevel, parseEffortValue, isValidNumericEffort, convertEffortValueToLevel, getEffortLevelDescription, resolvePickerEffortPersistence |
|
|
|
-
|
|
|
-### 已知限制
|
|
|
-
|
|
|
-以下模块因 Bun 运行时限制或极重依赖链,暂时无法或不适合测试:
|
|
|
-
|
|
|
-| 模块 | 问题 | 说明 |
|
|
|
-|------|------|------|
|
|
|
-| `Bun.JSONL.parseChunk` | 处理畸形行时无限挂起 | Bun 1.3.10 bug,错误恢复循环卡死;已跳过 parseJSONL 畸形行测试 |
|
|
|
-| `src/tools.ts` 部分函数 | `getAllBaseTools`/`getTools` 加载全量 tool | 导入链过重,mock 难度大 |
|
|
|
-| `src/tools/shared/spawnMultiAgent.ts` | 依赖 bootstrap/state + AppState + 50+ 模块 | mock 成本极高,投入产出比低 |
|
|
|
-| `src/utils/messages.ts` 部分函数 | `withMemoryCorrectionHint` 等 | 依赖 `getFeatureValue_CACHED_MAY_BE_STALE` |
|
|
|
+| 模块 | 问题 |
|
|
|
+|------|------|
|
|
|
+| `Bun.JSONL.parseChunk` | 畸形行时无限挂起(Bun 1.3.10 bug) |
|
|
|
+| `context.ts` 核心逻辑 | 依赖 bootstrap/state + git + 50+ 模块,mock 不可行 |
|
|
|
+| `tools.ts` (getAllBaseTools) | 导入链过重 |
|
|
|
+| `spawnMultiAgent.ts` | 50+ 依赖 |
|
|
|
+| `messages.ts` 部分函数 | 依赖 `getFeatureValue_CACHED_MAY_BE_STALE` |
|
|
|
+| UI 组件 (`screens/`, `components/`) | 需 Ink 渲染测试环境 |
|
|
|
|
|
|
-### Mock 策略总结
|
|
|
+### 5.6 Mock 模式
|
|
|
|
|
|
-通过 `mock.module()` + `await import()` 模式成功解锁了以下重依赖模块的测试:
|
|
|
+通过 `mock.module()` + `await import()` 解锁重依赖模块:
|
|
|
|
|
|
| 被 Mock 模块 | 解锁的测试 |
|
|
|
|-------------|-----------|
|
|
|
-| `src/utils/log.ts` | json.ts, tokens.ts, FileEditTool/utils.ts, permissions.ts, memoize.ts, PermissionMode.ts |
|
|
|
-| `src/services/tokenEstimation.ts` | tokens.ts |
|
|
|
-| `src/utils/slowOperations.ts` | tokens.ts, permissions.ts, memoize.ts, PermissionMode.ts |
|
|
|
-| `src/utils/debug.ts` | envValidation.ts, outputLimits.ts |
|
|
|
-| `src/utils/bash/commands.ts` | commandSemantics.ts |
|
|
|
-| `src/utils/thinking.js` | effort.ts |
|
|
|
-| `src/utils/settings/settings.js` | effort.ts |
|
|
|
-| `src/utils/auth.js` | effort.ts |
|
|
|
-| `src/services/analytics/growthbook.js` | effort.ts, tokenBudget.ts |
|
|
|
-| `src/utils/model/modelSupportOverrides.js` | effort.ts |
|
|
|
-
|
|
|
-**关键约束**:`mock.module()` 必须在每个测试文件中内联调用,不能从共享 helper 导入(Bun 在 mock 生效前就解析了 helper 的导入)。
|
|
|
-
|
|
|
-## 12. 后续测试覆盖计划
|
|
|
-
|
|
|
-> **已完成** — Phase 1-4 增加 321 tests (647 → 968),Phase 5 增加 209 tests (968 → 1177)
|
|
|
->
|
|
|
-> Phase 1-4 全部完成,详见上方 P3-P5 表格。
|
|
|
-> Phase 5 新增 12 个测试文件覆盖:effort、tokenBudget、displayTags、taggedId、controlMessageCompat、MCP normalization/envExpansion、gitConfigParser、formatBriefTimestamp、hyperlink、windowsPaths、notebook,详见 P6 表格。
|
|
|
-> 实际调整:Phase 3 中 `context.ts` 因极重依赖链(bootstrap/state + claudemd + git 等)且 `getGitStatus` 在 test 环境直接返回 null,替换为 `envValidation.ts`(更实用);Phase 4 中 GlobTool 纯函数不足,替换为 `commandSemantics.ts` + `destructiveCommandWarning.ts`。
|
|
|
-
|
|
|
-### 不纳入计划的模块
|
|
|
+| `src/utils/log.ts` | json, tokens, FileEditTool/utils, permissions, memoize, PermissionMode |
|
|
|
+| `src/services/tokenEstimation.ts` | tokens |
|
|
|
+| `src/utils/slowOperations.ts` | tokens, permissions, memoize, PermissionMode |
|
|
|
+| `src/utils/debug.ts` | envValidation, outputLimits |
|
|
|
+| `src/utils/bash/commands.ts` | commandSemantics |
|
|
|
+| `src/utils/thinking.js` | effort |
|
|
|
+| `src/utils/settings/settings.js` | effort |
|
|
|
+| `src/utils/auth.js` | effort |
|
|
|
+| `src/services/analytics/growthbook.js` | effort, tokenBudget |
|
|
|
+
|
|
|
+**约束**:`mock.module()` 必须在每个测试文件内联调用,不能从共享 helper 导入。
|
|
|
+
|
|
|
+## 6. 改进计划
|
|
|
+
|
|
|
+### 优先级排序
|
|
|
+
|
|
|
+| 优先级 | 任务 | 预期效果 |
|
|
|
+|--------|------|----------|
|
|
|
+| **高** | 修复 8 个 WEAK 文件的断言缺陷 | 消除假阳性风险 |
|
|
|
+| **高** | 补 `gitOperationTracking.test.ts` 的 analytics mock | 消除测试副作用 |
|
|
|
+| **高** | 验证 `envValidation.test.ts` 潜在 bug | 排除源码缺陷 |
|
|
|
+| **中** | 搭建 `tests/mocks/` 基础设施 | 为集成测试铺路 |
|
|
|
+| **中** | 编写 `tests/integration/tool-chain.test.ts` | 覆盖 Tool 注册→发现→执行链路 |
|
|
|
+| **中** | 补 `truncate.test.ts` CJK/emoji 测试 | 覆盖核心场景 |
|
|
|
+| **低** | 补 `claudemd.test.ts` 核心逻辑 | 提升 P0 模块覆盖率 |
|
|
|
+| **低** | 补 CLI 参数测试 (`main.tsx`) | 完成 P1 覆盖 |
|
|
|
+| **低** | 运行 `bun test --coverage` 建立基线 | 量化覆盖率 |
|
|
|
+
|
|
|
+### 不纳入计划
|
|
|
|
|
|
| 模块 | 原因 |
|
|
|
|------|------|
|
|
|
-| `query.ts` / `QueryEngine.ts` | 核心循环,需集成测试环境 |
|
|
|
+| `query.ts` / `QueryEngine.ts` | 核心循环,需完整集成环境 |
|
|
|
| `services/api/claude.ts` | 需 mock SDK 流式响应 |
|
|
|
-| `spawnMultiAgent.ts` | 50+ 依赖,mock 不可行 |
|
|
|
+| `spawnMultiAgent.ts` | 50+ 依赖 |
|
|
|
| `modelCost.ts` | 依赖 bootstrap/state + analytics |
|
|
|
| `mcp/dateTimeParser.ts` | 调用 Haiku API |
|
|
|
-| `screens/` / `components/` | UI 组件,需 Ink 渲染测试 |
|
|
|
-
|
|
|
-## 13. 参考
|
|
|
-
|
|
|
-- [Bun Test 文档](https://bun.sh/docs/cli/test)
|
|
|
-- 现有测试示例:`src/utils/__tests__/set.test.ts`, `src/utils/__tests__/array.test.ts`
|
|
|
+| `screens/` / `components/` | 需 Ink 渲染测试 |
|