Documentation

Step 21: 测试体系分析

21 — hermes-agent 测试体系全面分析

分析日期:2026-04-18 代码库:hermes-agent v0.10.0

1. 概述

hermes-agent 项目拥有一个大规模、高质量的测试体系:

指标 数值
测试文件数 585
测试用例数 (test 函数) 12,102
总测试代码行数 ~198,540
测试子目录 15
conftest.py 文件 3 (根 + gateway + e2e)
集成测试标记 7 个模块(pytestmark = pytest.mark.integration
异步测试 ~1,166 个 (@pytest.mark.asyncio)
Mock 使用次数 ~17,350 处

项目源代码约 ~200K 行(agent + tools + gateway + hermes_cli + root modules),测试代码与源代码的比例约为 1:1,覆盖率在量级上非常充分。


2. 测试架构

2.1 目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
tests/
├── conftest.py              # 全局 autouse fixture + 30s 超时
├── acp/                     # 8 files, 2,127 lines
├── agent/                   # 40 files, 17,554 lines
├── cli/                     # 38 files, 8,134 lines
├── cron/                    # 6 files, 2,956 lines
├── e2e/                     # 2 files, 456 lines
├── environments/            # 1 file, 164 lines
├── fakes/                   # 1 file, 301 lines (fake_ha_server)
├── gateway/                 # 152 files, 55,743 lines ← 最大
├── hermes_cli/              # 106 files, 31,637 lines
├── honcho_plugin/           # 4 files, 2,473 lines
├── integration/             # 7 files, 2,712 lines
├── plugins/                 # 5 files, 1,996 lines
├── run_agent/               # 44 files, 16,359 lines
├── skills/                  # 6 files, 2,113 lines
├── tools/                   # 134 files, 46,031 lines
└── (root 测试文件 27 个)

2.2 核心 Fixture — tests/conftest.py

三个 autouse fixture 构成隔离基石:

  1. _isolate_hermes_home — 将 HERMES_HOME 重定向到 tmp_path,确保测试永不写入 ~/.hermes/。同时清除 HERMES_SESSION_PLATFORMHERMES_GATEWAY_SESSIONOPENROUTER_API_KEY 等环境变量,重置插件单例。

  2. _ensure_current_event_loop — 为同步测试提供事件循环(Python 3.11+ 不再自动创建),支持网关测试中 asyncio.get_event_loop() 的使用,同时不干扰 pytest-asyncio 的异步测试。

  3. _enforce_test_timeout — 使用 SIGALRM 为每个测试强制设置 30 秒超时(Windows 跳过),防止子进程挂起阻塞整个测试套件。

辅助 fixture:

  • tmp_dirtmp_path 的别名
  • mock_config — 返回最小化配置字典

2.3 pytest 配置(pyproject.toml)

1
2
3
4
5
6
[tool.pytest.ini_options]
testpaths = ["tests"]
markers = [
    "integration: marks tests requiring external services (API keys, Modal, etc.)",
]
addopts = "-m 'not integration' -n auto"
  • 默认跳过集成测试-m 'not integration' 排除 @pytest.mark.integration 标记
  • 并行执行-n auto 使用 pytest-xdist 自动并行
  • 配置简洁,只有 integration 一个 marker

3. 测试分布热力图

3.1 按源模块映射

源模块 源码行数 测试目录 测试文件数 测试用例数 覆盖评估
run_agent.py 11,603 tests/run_agent/ 44 ~759 🟢 深
cli.py 10,275 tests/cli/ 38 ~447 🟡 中
agent/ ~25,000 tests/agent/ 40 ~1,319 🟢 深
tools/ ~37,000 tests/tools/ 134 ~3,130 🟢 深
gateway/ ~35,000 tests/gateway/ 152 ~2,965 🟢 深
hermes_cli/ ~42,000 tests/hermes_cli/ 106 ~2,059 🟡 中
cron/ ~1,500 tests/cron/ 6 ~167 🟡 中
hermes_state.py 1,238 root tests 1 ~137 🟢 深
model_tools.py 562 root tests 1 ~23 🟡 中
toolsets.py 702 root tests 1 ~22 🟡 中
trajectory_compressor.py 1,462 root tests 2 ~35 🟡 中
batch_runner.py 1,290 root tests 1 ~12 🟡 中
acp_adapter/ ~500 tests/acp/ 8 ~127 🟢 深

3.2 无测试覆盖的源模块

以下是零测试文件引用的源模块(高风险):

模块 行数 说明
rl_cli.py ~200 RL 训练 CLI 入口
mini_swe_runner.py ~300 Mini SWE 运行器
agent/copilot_acp_client.py 586 ACP 客户端
agent/manual_compression_feedback.py 49 手动压缩反馈(小文件)
agent/retry_utils.py 57 重试工具函数(小文件)
agent/trajectory.py 56 轨迹保存(小文件)
tools/binary_extensions.py 42 二进制扩展名(小文件)
tools/neutts_synth.py 104 NEUTTS 合成
tools/path_security.py 43 路径安全(小文件)
tools/xai_http.py 12 xAI HTTP(极小文件)
hermes_cli/cli_output.py 78 CLI 输出格式化
hermes_cli/memory_setup.py 457 记忆设置向导
hermes_cli/pairing.py 97 配对逻辑
gateway/restart.py 20 网关重启(极小文件)
environments/ (多个) ~2,000 终端后端环境

4. 测试风格评估

4.1 最大测试文件 Top 10

测试文件 行数 对应源模块
tests/run_agent/test_run_agent.py 4,209 run_agent.py
tests/tools/test_mcp_tool.py 3,181 tools/mcp_tool.py
tests/gateway/test_feishu.py 2,967 gateway/platforms/feishu.py
tests/gateway/test_voice_command.py 2,680 gateway/voice
tests/gateway/test_api_server.py 2,093 gateway/platforms/api_server.py
tests/gateway/test_matrix.py 1,954 gateway/platforms/matrix.py
tests/gateway/test_slack.py 1,766 gateway/platforms/slack.py
tests/agent/test_anthropic_adapter.py 1,657 agent/anthropic_adapter.py
tests/hermes_cli/test_runtime_provider_resolution.py 1,414 hermes_cli/runtime_provider.py
tests/test_hermes_state.py 1,377 hermes_state.py

4.2 测试模式分析

Mock 使用极广泛(17,350 处),主要集中在:

  • unittest.mock.patch / monkeypatch — 隔离外部依赖(OpenAI API, 文件系统, 网络)
  • MagicMock / AsyncMock — 模拟 LLM 客户端响应和工具返回值
  • monkeypatch.setenv / monkeypatch.delenv — 环境变量隔离
  • tmp_path + _isolate_hermes_home — 文件系统沙箱

测试命名规范:统一的 test_<功能单位>_<场景>_<预期> 模式,例如:

  • test_sanitize_fts5_preserves_quoted_phrases
  • test_blocked_tool_returns_error_and_skips_dispatch
  • test_ipv4_preference_double_patch_is_safe

断言风格:直接使用 assert 语句(非 assertEqual 等 unittest 方法),这是 pytest 惯用风格,断言信息由 pytest 的 assert rewriting 提供。

Fixture 模式:大量模块级 fixture(如 db, agent, mcp_server_e2e, sessions_dir),在 conftest.py 和各测试文件内定义,复用性良好。

4.3 异步测试

约 1,166 个 @pytest.mark.asyncio 测试,主要分布在:

  • tests/gateway/ — 平台适配器的异步消息处理
  • tests/agent/ — LLM 客户端异步调用
  • tests/tools/test_mcp_tool.py — MCP 工具的异步协议

4.4 集成测试

7 个模块级 pytestmark = pytest.mark.integration 标记(全部在 tests/integration/),默认被 addopts = "-m 'not integration'" 排除。涉及外部服务:

  • Modal 终端
  • Daytona 终端
  • Checkpoint 恢复
  • Home Assistant 集成
  • Web 工具实时调用
  • 语音通道端到端
  • Batch Runner

5. 关键风险分析

5.1 高风险:零覆盖模块

优先级 模块 风险说明
🔴 P0 hermes_cli/memory_setup.py (457行) 记忆系统设置涉及数据迁移和安全,无测试是严重遗漏
🔴 P0 agent/copilot_acp_client.py (586行) ACP 协议客户端,集成入口但无单元测试
🟠 P1 rl_cli.py RL 训练入口,生产代码路径
🟠 P1 mini_swe_runner.py SWE 基准运行器
🟡 P2 tools/neutts_synth.py TTS 合成链路
🟡 P2 environments/ Docker/SSH/Modal/Singularity 终端后端

5.2 中风险:低覆盖模块

模块 测试文件数 说明
cli.py (10,275行) 38个 每个测试文件平均仅 214 行,对巨型入口文件覆盖可能不够深
gateway/run.py (9,892行) 引用102个 主循环逻辑复杂,需要重点验证错误路径
hermes_cli/main.py (6,552行) 引用42个 CLI 入口参数解析和子命令分发
hermes_cli/setup.py (3,235行) 引用28个 交互式设置向导
gateway/platforms/qqbot.py (1,960行) 1个 QQ 机器人平台覆盖极低

5.3 结构性风险

  1. 巨型单文件测试test_run_agent.py(4,209行)和 test_mcp_tool.py(3,181行)可能包含大量重复 fixture,建议拆分。
  2. E2E 仅 2 文件 / 456 行:端到端测试覆盖薄弱。
  3. environments/ 仅 1 文件 / 164 行:终端后端(Docker, SSH, Modal, Daytona)是安全敏感模块,但测试极少。
  4. 无覆盖率收集pyproject.toml 未配置 coverage,无法量化实际行覆盖率。

6. TOP 10 测试改进建议

1. 🔴 为 hermes_cli/memory_setup.py 添加测试

457 行的记忆系统设置涉及数据迁移、用户配置、安全路径,零测试是最严重的覆盖漏洞。应测试:配置解析、迁移路径、错误恢复。

2. 🔴 为 agent/copilot_acp_client.py 添加测试

586 行的 ACP 客户端是 VS Code/Zed 集成的核心入口。建议添加:协议握手、消息序列化、错误恢复、超时处理的单元测试。

3. 🟠 引入覆盖率收集

pyproject.toml[tool.pytest.ini_options] 中添加 --cov=. 配置,或使用 coverage run。无覆盖率数据意味着无法量化真实覆盖水平。

4. 🟠 拆分巨型测试文件

test_run_agent.py(4,209行)和 test_mcp_tool.py(3,181行)按功能域拆分为多个文件,提高可读性和并行执行效率。例如 test_run_agent_retry.py, test_run_agent_context.py 等。

5. 🟠 增加终端后端(environments/)测试

Docker、SSH、Modal、Daytona、Singularity 后端是安全敏感模块(命令注入、路径穿越风险),仅 164 行测试远远不够。至少需要:沙箱隔离验证、超时处理、环境变量传递。

6. 🟡 为 rl_cli.pymini_swe_runner.py 添加基础测试

即使是入口脚本,也应测试参数解析、环境检测、错误退出路径。

7. 🟡 加强 gateway/platforms/qqbot.py 测试

1,960 行源码仅有 1 个测试文件引用。QQ 机器人平台涉及消息格式化、事件处理、认证等关键逻辑。

8. 🟡 扩展 E2E 测试套件

当前仅 2 文件 456 行 E2E 测试。建议增加:完整会话流程、多平台消息往返、工具调用链条的端到端验证。

9. 🟢 添加更多 pytest markers

当前只有 integration 一个 marker。建议增加:

  • slow — 标记执行超过 1 秒的测试
  • network — 标记需要网络的测试(即使不是完整集成)
  • platform:telegram/discord/... — 按平台标记,方便选择性运行

10. 🟢 为 tools/path_security.py 添加安全测试

虽然仅 43 行,但这是路径安全模块(防止路径穿越攻击)。安全关键代码即使很小也应 100% 覆盖。


7. 总结

hermes-agent 的测试体系在规模上非常出色——12,102 个测试用例、198K 行测试代码,覆盖了主要模块的核心路径。autouse fixture 机制确保了测试隔离的可靠性,Mock 使用广泛且规范。

核心优势

  • 量级充足(测试代码 ≈ 源代码量级)
  • 隔离机制完善(_isolate_hermes_home + 30s 超时 + 环境清理)
  • 并行执行支持良好(-n auto
  • 集成测试与单元测试分离(integration marker)

核心待改进

  • 缺少量化覆盖率数据(无 coverage 配置)
  • 少量安全/入口模块零覆盖(4 个 P0/P1 级别)
  • 巨型测试文件需要拆分
  • E2E 和 environments 后端测试薄弱