07 - 测试策略与 CI
学习目标
本章聚焦 Hermes Agent 的测试策略与 CI 架构。你将了解:
- ~17k 测试如何通过 per-file 隔离高效运行
- 技能测试的规范要求(仅 stdlib + pytest + mock)
- GitHub Actions CI 的 SHA 固定依赖与审计
- 发布流程自动化
前置知识
无特定前置知识。
项目实践
测试规模
截至 2026-05,Hermes 拥有:
- ~17k 测试用例
- ~900 测试文件
这种规模的测试集需要高效的运行策略。
测试运行器架构
scripts/run_tests.sh 自动探测虚拟环境并调用并行运行器:
# 自动探测 .venv / venv# 调用 scripts/run_tests_parallel.pyrun_tests_parallel.py 关键设计:
| 策略 | 实现 |
|---|---|
| Per-file 隔离 | 每个测试文件在独立子进程中运行 |
| 干净环境 | env -i:TZ=UTC、LANG=C.UTF-8、PYTHONHASHSEED=0 |
| 虚拟环境 | 优先 .venv,回退 venv,再回退 ~/.hermes/hermes-agent/venv |
| Live Gateway | 可选通过 ~/.hermes/pytest_live_guard.py 加载 live gateway 插件 |
Per-file 隔离确保单个测试文件的崩溃或污染不影响其他测试文件。
技能测试规范
tests/skills/test_<skill>_skill.py 是技能测试的规范文件:
规范要求:
- 仅使用 stdlib + pytest + mock
- 禁止实时网络调用:所有外部 API 调用必须 mock
- 技能测试必须在干净环境中通过
为什么不用实时网络? 技能测试需要可重复、快速、离线可运行。实时网络调用导致测试不稳定且慢。
测试目录结构
tests/ 目录按功能组织:
| 目录 | 测试内容 |
|---|---|
tests/skills/ | 技能功能测试 |
tests/tools/ | 工具功能测试 |
tests/agent/ | Agent 核心循环测试 |
tests/gateway/ | 网关测试 |
tests/cron/ | Cron 调度器测试 |
CI:GitHub Actions
关键策略:
| 策略 | 实现 |
|---|---|
| SHA 固定依赖 | GitHub Actions 使用 SHA 而非 tag 引用 action,防止供应链攻击 |
| 审计 | CI 日志记录所有依赖版本 |
发布流程
scripts/release.py 自动化发布:
- 版本号递增
- CHANGELOG 生成
- Git tag 创建
- 发布到 PyPI(如果适用)
问题与规避
大规模测试运行时间长
问题:~900 个测试文件顺序运行需要很长时间。
对策:run_tests_parallel.py 将测试文件分发到多个子进程并行运行。Per-file 隔离确保并行安全。
技能测试的网络 mock 不完整
问题:技能需要调用外部 API,但测试中 mock 可能不完整。
对策:技能测试标准禁止实时网络调用。所有外部依赖必须 mock。如果技能确实在真实环境中测试,使用 live gateway 插件(pytest_live_guard.py)在 CI 中可选运行。
设计取舍
Per-file 隔离 vs 进程内运行
| 方案 | 优势 | 代价 |
|---|---|---|
| Per-file 隔离(Hermes) | 测试间完全隔离、一个测试崩溃不影响其他 | 子进程启动开销 |
| 进程内运行 | 启动快、资源共享 | 测试间可能互相干扰、状态泄漏 |
Hermes 选择 per-file 隔离,因为 ~17k 测试中任何单个测试的崩溃都不应该导致整个测试套件失败。隔离带来的开销在 CI 环境中是可接受的。
参考来源
- 源码验证:
tests/目录结构、scripts/run_tests.sh、scripts/run_tests_parallel.py、AGENTS.md测试策略章节