跳转到内容

测试策略与内部验证

测试策略与内部验证

学习目标

本章要解决什么问题:理解 ECC 如何对 246 个技能、76 个命令、40+ 钩子等纯 Markdown/JSON 内容实现 997+ 内部测试保障。

读完本章后,你将了解:

  • 纯 Markdown 内容的测试策略
  • 目录镜像结构与命名约定
  • 目录计数 CI 强制
  • 安装 Manifest 验证

前置知识

本章无外部依赖知识,建议先了解 ECC 的组件分类:


项目实践

测试对象:不是代码,是内容

ECC 的主要资产是 Markdown 文件(技能、代理、命令、规则)和 JSON 配置(钩子、Manifest)。这些内容的”测试”不是运行逻辑,而是验证结构完整性:

测试目录结构

ECC 的 tests/ 目录镜像 scripts/ 的结构:

tests/
├── lib/ # scripts/lib/ 的镜像
│ ├── utils.test.js
│ ├── package-manager.test.js
│ ├── install/ # 安装管道测试
│ └── skill-evolution/ # 技能演进测试
├── hooks/ # 钩子集成测试
│ └── hooks.test.js
└── run-all.js # 测试入口

运行方式

Terminal window
# 运行所有测试
node tests/run-all.js
# 运行单个测试
node tests/lib/utils.test.js
node tests/hooks/hooks.test.js

测试类型

1. 文件存在性测试

// 伪代码:验证每个技能目录都有 SKILL.md
for (const skillDir of readdirSync('skills/')) {
assert(exists(path.join('skills/', skillDir, 'SKILL.md')))
}

2. Frontmatter 格式验证

// 伪代码:验证代理定义的 frontmatter
for (const agentFile of readdirSync('agents/')) {
const content = read(`agents/${agentFile}`)
assert(matchesYamlFrontmatter(content))
const meta = parseFrontmatter(content)
assert(meta.name, '必须有 name 字段')
assert(meta.description, '必须有 description 字段')
assert(meta.tools, '必须有 tools 字段')
assert(meta.model, '必须有 model 字段')
}

3. 目录计数一致性: CHANGELOG 中声明的数量必须与目录实际文件数匹配。

4. Manifest 路径存在性install-modules.json 中声明的所有路径必须在仓库中存在。

5. Schema 验证: Provenance 文件、安装状态等 JSON 文件必须符合对应 Schema。

目录计数 CI 强制

ECC 的 CI 流程强制检查目录计数:

skills/ 目录数 = CHANGELOG 中声明的技能数
agents/ 目录数 = CHANGELOG 中声明的代理数
commands/ 文件数 = CHANGELOG 中声明的命令数

如果任何一项不匹配,CI 失败。这确保了:

  • 文档与代码一致性
  • CHANGELOG 数字不会过时
  • 新增/删除组件时必须更新 CHANGELOG

钩子集成测试

tests/hooks/hooks.test.js 测试钩子系统的集成行为:

  • hooks.json 格式正确
  • 所有引用的脚本文件存在
  • 异步钩子超时配置合理
  • 钩子 ID 唯一

997+ 测试的来源

“997+ 内部测试”不是传统的单元测试数,而是:

  • 文件存在性检查(246 个技能 × 每个多个检查项)
  • Frontmatter 格式验证(61 个代理 + 76 个命令)
  • Manifest 路径检查(模块 × 路径数)
  • Schema 验证(Provenance、安装状态)
  • 目录计数检查
  • 钩子格式和引用检查

这些检查的总数超过 997。


问题与规避

测试不验证内容正确性

问题:测试只验证文件存在和格式,不验证 SKILL.md 中的指令是否正确。

ECC 的规避

  • 内容正确性通过代码审查(code-reviewer 代理)保证
  • 社区 PR 流程允许用户报告无效或过时的技能
  • /skill-health 命令运行时检查技能的可加载性

新增技能忘记更新 Manifest

问题:新增技能但未添加到 install-modules.json,导致无法安装。

规避方案

  • CI 验证 install-modules.json 中的路径与 skills/ 目录的一致性
  • CONTRIBUTING.md 中要求新增技能时同时更新 Manifest

目录计数与 CHANGELOG 不一致

问题:删除技能但未更新 CHANGELOG 中的数字。

规避方案

  • CI 强制检查目录计数与 CHANGELOG 的一致性
  • PR 模板提醒贡献者更新数字

设计取舍

为什么测试数如此高(997+)?

因为 ECC 的主要资产是内容文件(Markdown/JSON),每个文件都需要独立的验证:

  • 每个技能需要验证:文件存在 + frontmatter 格式 + 非空 + Manifest 路径 = 4+ 个检查
  • 246 个技能 × 4 检查 = ~1000 个检查点

这不是过度测试:纯内容项目的测试策略与代码项目不同。内容的”bug”通常是结构性的(文件缺失、格式错误),而非逻辑性的。

为什么不用 Jest/Vitest?

ECC 使用 Node.js 原生 assert 模块:

  • 优势:零依赖,node tests/run-all.js 即可运行
  • 代价:没有丰富的断言库和报告格式
  • 为什么:ECC 是 CommonJS 项目,不引入额外的测试框架依赖

参考来源

  • 源码验证: tests/ 目录 — 测试套件
  • 源码验证: tests/run-all.js — 测试入口
  • 源码验证: scripts/ci/validate-skills.js — CI 技能验证
  • 源码验证: scripts/ci/validate-install-manifests.js — CI Manifest 验证
  • 源码验证: package.jsontest 命令定义