EverOS 测试规范实战指南:目录镜像、pytest-asyncio 与 80% 覆盖率门禁
2026/9/23 1:23:33 网站建设 项目流程

EverOS 测试规范实战指南:目录镜像、pytest-asyncio 与 80% 覆盖率门禁

【免费下载链接】EverOSOne portable memory layer for every AI agent: local-first, Markdown-native, user-owned, and self-evolving across apps, tools, and workflows.项目地址: https://gitcode.com/gh_mirrors/ev/EverOS

本指南基于 EverOS 仓库.claude/rules/testing.md测试规则,结合仓库中真实的Makefilepyproject.tomlconftest.py与测试用例,系统讲解 EverOS 的测试分层结构、异步测试写法、Marker 分级策略、fixture 隔离机制与覆盖率门禁,帮助你在提交代码前一次性通过本地与 CI 的双重检验。

EverOS 是一个面向 AI Agent 的本地优先、Markdown 原生的记忆层框架(见 README.md),其测试体系直接映射了源码的三层架构。.claude/rules/testing.md是该仓库对 AI 编码助手与人类开发者统一的测试约束文件,本文以它为骨架,深入仓库源码与测试用例,给出可复现、可验证的完整实践。

一、测试金字塔与目录镜像约定

规则原文要求:"Tests mirror the source layout",即测试目录与源码目录逐包镜像:

tests/unit/test_<layer>/... # 单元测试,镜像 src/everos/ tests/integration/... # 集成测试 tests/e2e/... # 端到端测试
  • tests/unit/镜像src/everos/包结构:源码在src/everos/memory/cascade/worker.py,测试就在tests/unit/test_memory/test_cascade/test_worker.py;源码src/everos/component/embedding/对应tests/unit/test_component/test_embedding/
  • "Put a test next to where its subject lives in the mirror"——测试与被测对象在镜像中一一对应,查找测试时无需猜测路径。

从仓库实际布局看(tests/),tests/unit/下与src/everos/顶层包一一对应有test_component/test_config/test_core/test_entrypoints/test_infra/test_memory/test_service/等目录,而tests/integration/下则是跨层场景(如test_memorize_integration.py驱动service.memorize.memorize()全链路)、tests/e2e/下是完整应用生命周期测试(如test_add_flush_agent_pipeline_e2e.py)。三层金字塔从"单模块快速验证"到"全链路真实依赖",层层递进。

二、pytest-asyncio auto 模式:无需装饰器的异步测试

EverOS 的核心链路(记忆写入、Cascade 扫描、OME 调度)几乎全部是异步代码,因此规则明确约定pytest-asyncio处于auto模式:

  • 写法:直接写async def test_*,无需任何@pytest.mark.asyncio标记。
  • 配置依据:见 pyproject.toml 中的[tool.pytest.ini_options]asyncio_mode = "auto"

仓库中大量用例印证了这一点,例如 tests/unit/test_memory/test_events.py 中def test_user_pipeline_started_topic_is_module_qualified()这类同步断言,以及 tests/unit/test_memory/test_cascade/test_worker.py 中大量直接async def test_...的用例。

配套的 pytest 基础配置同样在 pyproject.toml:

[tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] python_functions = ["test_*"] asyncio_mode = "auto" addopts = "-v --tb=short -m 'not slow and not live_llm'"

要点说明:

  • addopts默认排除了slowlive_llm两组标记,普通pytest/make test默认只跑"快速且无外部凭据"的用例;
  • filterwarnings = ["error", ...]将警告升级为错误,强制依赖库的已知无害告警必须显式ignore(如 jieba 0.42.1 的转义序列警告、aiosqlite 生命周期警告),保证套件在严格模式下依然绿。

三、Marker 分级:slow 与 live_llm

规则规定两个自定义标记,均在 pyproject.toml 中登记:

标记含义默认运行手动运行
@pytest.mark.slow耗时 ≥ ~10 秒的用例排除pytest -m slow
@pytest.mark.live_llm需要真实 LLM/embedder/reranker 凭据,消耗 token排除pytest -m live_llm

核心纪律:单元测试必须快速且零凭据;任何需要真实外部服务的用例要么打上标记,要么下沉到integration/e2e目录。例如 tests/e2e/test_search_endpoint_e2e.py 中 21 处标记组合(slow+live_llm),这类用例依赖 tests/e2e/conftest.py 在导入期load_dotenv读取真实.env凭据——与单元测试的"无凭据"原则形成互补。

四、Fixtures 与隔离:根 conftest 的缓存重置

规则指出:"Shared fixtures live in the nearestconftest.py. The root conftest resets module caches (settings/logging/datetime) per test." 仓库 tests/conftest.py 用一组autouse=True的 fixture 实现了全局隔离:

  1. _isolate_everos_root:通过monkeypatch.setenv("EVEROS_ROOT", str(tmp_path))将每个测试钉在独立的临时内存根上,防止测试误读开发者本机的everos.toml
  2. _reset_settings_cache:清空load_settings.cache_clear()dt_module._display_tz.cache_clear()(生产热路径用functools.cache缓存),并structlog.reset_defaults(),避免日志配置跨用例泄漏;
  3. _reset_embedding_capability_singleton/_reset_rerank_capability_singleton/_reset_multimodal_capability_singleton:将三个 capability 惰性单例预置为available=False,保证套件密闭性(hermetic),不随宿主环境变化而翻转测试结果。

这解释了规则中"rely on that for isolation rather than mutating globals"的含义——不要在自己测试里改全局状态,交给根 conftest 的自动 fixture 处理即可。跨套件共享的数据 fixture(如 LoCoMolong_conversation)也按"最近 conftest"原则放在根 tests/conftest.py(scope="session"),因为tests/e2e/tests/integration/search/都需要它,而 conftest 只能向子目录级联。

五、模块 Docstring:钉住测试契约

每个测试文件顶部都必须有模块级 docstring,说明该文件钉住了什么契约(contract)。这是规则明确要求、仓库处处落实的风格:

  • tests/unit/test_memory/test_cascade/test_worker.py 开头声明:"Tests forCascadeWorkerretry classification + optimize scheduler",随后列出五个分支行为(重试上限、非服务错误立即失败、成功标记、未知 kind 等);
  • tests/integration/test_memorize_integration.py 声明用FakeLLMClient驱动service.memorize.memorize()全链路,且明确"OME strategies 通过mock_aextract静默,本文件聚焦同步边界 + 管线 + md 路径";
  • tests/e2e/conftest.py 的 docstring 详述了各 fixture 的职责与命名约定(如"本文件不定义cascade_runtime,避免与test_cascade_integration.py的本地 fixture 撞名")。

写新测试时,第一行就回答"这个文件钉住什么行为",审阅者与后续维护者能立刻判断测试的边界与意图。

六、覆盖率门禁:make cov 与 80% 底线

规则要求"make covenforces 80% (--cov-fail-under=80)"。对应的 Makefile 目标在 Makefile:

cov: uv run pytest tests/unit tests/integration --cov=src/everos --cov-report=term-missing --cov-branch --cov-fail-under=80

注意细节:

  • 同时跑 unit + integration:注释说明当前 unit-only 覆盖率约 87%,unit+integration 约 91%,80% 阈值保留约 10 个百分点余量供正常波动;
  • 分支覆盖率--cov-branch开启分支覆盖;pyproject.toml 的[tool.coverage.run]branch = trueomit = ["**/__init__.py"][tool.coverage.report]fail_under = 80show_missing = true,同时排除if TYPE_CHECKING:@abstractmethodpragma: no cover行。

因此"新代码不应把覆盖率拉到门禁以下"是硬约束——CI 与本地同一套阈值,本地红了 CI 必红。

七、提交前检查清单:make test / make integration / ci

规则的收尾要求:"Runmake test(unit) andmake integrationbefore pushing; both run in CI." 对应的目标:

test: uv run pytest tests/unit -v integration: uv run pytest tests/integration -v ci: lint test integration package

完整 CI 编排见 Makefile 与 Makefile 的lint(ruff 检查 + 格式化 + import-linter + 资源/文件大小/命名/时区纪律扫描 + OpenAPI 漂移校验)。推荐的最小提交前流程:

  1. make format统一格式;
  2. make test跑单元测试(默认已排除 slow/live_llm,快速);
  3. make integration跑跨层集成测试;
  4. make cov确认覆盖率不低于 80%;
  5. 有把握时直接make ci复刻 CI 全流程(lint + test + integration + package)。

其中make integration的幂等性、并发安全等行为在 tests/integration/ 中有大量专项用例覆盖,例如 test_memorize_concurrent_session_lock.py(会话锁)、test_memorize_window_segmentation.py(窗口切分),与单元层形成互补。

总结

EverOS 的测试体系可以用一句话概括:目录镜像定位、auto 异步免装饰、双 marker 分级、autouse fixture 全局隔离、docstring 钉契约、80% 分支覆盖率兜底、本地与 CI 同一条命令链。无论你是为 EverOS 贡献新特性、编写新的记忆策略,还是仅仅想跑通这套测试来理解框架行为,遵循.claude/rules/testing.md都能让你的改动稳定、快速、可审计地合入。

快速参考

  • 规则文件:.claude/rules/testing.md
  • pytest 配置与 marker 定义:pyproject.toml
  • 测试命令与覆盖率门禁:Makefile
  • 根级 fixture(隔离与共享数据):tests/conftest.py
  • 单元测试示例(docstring + async):tests/unit/test_memory/test_cascade/test_worker.py
  • 集成测试示例(FakeLLM 全链路):tests/integration/test_memorize_integration.py
  • e2e 依赖与 marker 组合:tests/e2e/conftest.py、tests/e2e/test_search_endpoint_e2e.py

【免费下载链接】EverOSOne portable memory layer for every AI agent: local-first, Markdown-native, user-owned, and self-evolving across apps, tools, and workflows.项目地址: https://gitcode.com/gh_mirrors/ev/EverOS

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询