ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CAI 框架测试指南:从 uv 环境到 inline-snapshot 快照的完整测试工作流

CAI 框架测试指南:从 uv 环境到 inline-snapshot 快照的完整测试工作流 CAI 框架测试指南从 uv 环境到 inline-snapshot 快照的完整测试工作流【免费下载链接】caiCybersecurity AI (CAI), the framework for AI Security项目地址: https://gitcode.com/GitHub_Trending/cai3/cai本篇指南围绕 CAICybersecurity AI框架的测试体系展开完整梳理tests/README.md所定义的测试流程并结合仓库中的 Makefile、pyproject.toml 与 tests 目录源码深入讲解环境准备、make tests命令的实际调用链、inline-snapshot 快照的创建与修复机制以及驱动数千条测试运行的全局 fixtures 与假模型基础设施。读完本文你将掌握 CAI 框架从零开始跑通测试、正确维护快照断言、并在本地复现 CI 质量门禁的完整实战能力。环境准备uv 与 make syncCAI 框架使用 uv 作为 Python 项目管理与依赖解析工具。运行任何测试之前需要确保本机已安装uv并建议先执行依赖同步make sync该命令在 Makefile 中定义为sync: uv sync --all-extras --all-packages --group dev关键点说明--all-extras安装项目声明的全部可选依赖pyproject.toml 中的voice、viz等 extras--all-packages同步工作区workspace内全部包包括[tool.uv.workspace]中注册的agents成员见 pyproject.toml--group dev安装开发依赖组其中与测试直接相关的包括pytest、pytest-asyncio、pytest-mock、coverage以及inline-snapshot0.20.7见 pyproject.toml。项目要求 Python3.9pyproject.tomluv会自动解析并创建独立的虚拟环境无需手动管理 venv。运行测试make tests 与底层调用链环境同步完成后运行整套测试只需一条命令make tests它在 Makefile 中实际执行tests: uv run pytest也就是说make tests本质上是uv run pytestuv 在项目锁定的虚拟环境中启动 pytest随后 pytest 会加载项目根目录 pyproject.toml 中的[tool.pytest.ini_options]配置[tool.pytest.ini_options] asyncio_mode auto asyncio_default_fixture_loop_scope session filterwarnings [ ignore:coroutine test_async_input_filter_fails.locals.invalid_input_filter was never awaited:RuntimeWarning, ] markers [ allow_call_model_methods: mark test as allowing calls to real model implementations, ]这些配置的含义与影响asyncio_mode auto配合pytest-asyncio所有async def test_*函数会被自动识别为异步测试无需手动添加pytest.mark.asyncio这解释了为何 tests/agents/test_agent_runner.py、tests/voice/test_pipeline.py 等文件中的异步用例可以直接编写asyncio_default_fixture_loop_scope session异步 fixtures 默认在 session 级事件循环中执行避免每个用例重复创建事件循环的开销markers注册了allow_call_model_methods标记与 tests/conftest.py 中的防护逻辑配合详见下文测试基础设施filterwarnings显式忽略一条已知的 RuntimeWarning避免特定异步 filter 用例产生噪音。测试目录地图CAI 的测试按被测模块组织在 tests 下从目录结构可以清晰看出框架的能力边界目录覆盖主题代表文件tests/agentsAgent 配置、钩子、推理、守卫guardrails、工具轮次test_agent_inference.py、test_guardrails.pytests/cliCLI 入口与流式输出test_cli_streaming.pytests/commandsREPL 子命令agent/config/cost/model/parallel 等与 MCP 持久化test_command_agent.py、test_mcp_persistence.pytests/core模型层Responses/ChatCompletions 转换器、流式解析、run 执行test_openai_responses_converter.py、test_run_step_execution.pytests/mcpMCP 连接、缓存、追踪与服务器错误处理test_connect_disconnect.py、test_server_errors.pytests/toolsFunctionTool、handoff、输出工具、Linux 命令工具与会话test_function_tool.py、test_tool_generic_linux_command.pytests/tracing追踪处理器、span/trace 生命周期、错误流test_tracing.py、test_tracing_errors_streamed.pytests/voice语音流水线、STT/TTS 与工作流test_pipeline.py、test_workflow.pytests/others配置、严格模式、文档解析、可视化等test_config.py、test_strict_schema.py另外tests/commands/pytest.ini 为 REPL 命令测试提供了独立的 pytest 配置integration、slow、unit三类 marker 及--durations10等 addopts说明命令层用例被单独组织以便按需筛选运行。inline-snapshot 快照测试机制tests/README.md特别强调项目对部分测试采用inline-snapshot内联快照方案。与传统的文件级快照如 pytest-snapshot不同inline-snapshot 将期望值直接内联写入测试源码的snapshot(...)调用中代码即断言、断言即文档。仓库中的快照用例通过搜索可以确认以下测试文件导入了from inline_snapshot import snapshot并使用快照断言tests/mcp/test_mcp_tracing.pytests/others/test_pretty_print.pytests/tracing/test_agent_tracing.py、test_responses_tracing.py、test_tracing.py、test_tracing_errors.py、test_tracing_errors_streamed.pytests/voice/test_workflow.py从文件分布可以看出快照主要被用于两类场景一是追踪数据导出结果span/trace 的序列化结构时间戳、ID 等不稳定字段会被剔除后与快照比对二是富文本/可视化输出如 pretty print 的排版结果这类输出结构复杂、手工断言繁琐快照是最合适的断言方式。修复快照make snapshots-fix当你的改动导致已有快照测试失败时例如追踪导出的字段顺序或内容发生变化需要先人工确认新输出是正确的再修复快照make snapshots-fix对应 Makefile 中的实现snapshots-fix: uv run pytest --inline-snapshotfix--inline-snapshotfix会让 pytest 在运行测试时把失败用例的实际输出直接写回测试源码中的snapshot(...)占位将快照更新为当前真实值。创建快照make snapshots-create注意与 README 的差异当你编写了新的快照测试即snapshot()调用中尚未填入期望值时需要创建初始快照make snapshots-create对应 Makefile 中的实现snapshots-create: uv run pytest --inline-snapshotcreate--inline-snapshotcreate会为所有空快照填充首次运行产生的输出。使用注意tests/README.md中写的是make snapshots-update但从 Makefile 的源码结构看仓库实际提供的目标是snapshots-create创建/更新空快照与snapshots-fix修复失败快照并未定义名为snapshots-update的目标。因此 README 中的make snapshots-update可以推断为笔误实际操作请使用make snapshots-create。快照格式化约定pyproject.toml 还定义了快照写入源码时的格式化命令[tool.inline-snapshot] format-command ruff format --stdin-filename {filename}即每次快照被 fix/create 写回后inline-snapshot 会自动调用ruff format对源码片段做格式化保证快照内容与项目统一的代码风格一致ruff 行宽 100见 pyproject.toml。修复/创建后的验证流程官方文档给出的标准工作流是改动代码 → 运行make tests确认失败 → 判断新输出是否正确 →make snapshots-fix修复或make snapshots-create创建 → 再次运行make tests验证全绿。修复快照后必须重新跑一遍测试确保没有连带破坏其他用例。测试基础设施conftest.py 的全局 fixturesCAI 的测试并非简单的单元断言集合tests/conftest.py 通过 4 个 autouse fixtures 构建了一套强约束的测试环境理解它们有助于你正确编写新测试。1. 追踪处理器注入与隔离session 级 fixturesetup_span_processor在全部测试开始前将 tests/testing_processor.py 中定义的线程安全内存处理器SPAN_PROCESSOR_TESTING注册为全局追踪处理器set_trace_processors([SPAN_PROCESSOR_TESTING])。随后clear_span_processor在每个用例执行前强制清空 span/trace 集合保证用例之间互不污染shutdown_trace_provider则在 session 结束时关闭全局 TraceProvider。2. OpenAI 默认设置重置clear_openai_settings在每个用例前重置_openai_shared模块的默认 API Key、默认客户端与use_responses_by_default标志避免用例间残留全局状态该模块实现位于 src/cai/sdk/agents/models/_openai_shared.py。3. 禁用真实模型调用关键防护disable_real_model_clients是最重要的一道防线除非测试显式标记了pytest.mark.allow_call_model_methods否则它会把OpenAIResponsesModel与OpenAIChatCompletionsModel的get_response/stream_response全部 monkeypatch 成pytest.fail(Real models should not be used in tests!)。这意味着任何未标记的测试只要试图触达真实模型 API 都会立即失败——从源码结构可以推断这是为了防止测试意外产生外部 API 调用费用与网络依赖同时也强制开发者依赖测试替身而非真实模型。测试替身FakeModel 与 SpanProcessorForTests为了让测试在不触碰真实模型的前提下覆盖完整 Agent 执行链路仓库提供了两套核心替身FakeModel模型替身tests/fake_model.py 中的FakeModel实现了Model接口定义于 src/cai/sdk/agents/models/interface.py支持set_next_output(...)/add_multiple_turn_outputs(...)预置单轮或多轮模型输出可注入Exception以模拟模型报错get_response(...)/stream_response(...)完整实现非流式与流式两种调用路径并记录last_turn_argssystem_instructions、input、model_settings、tools、output_schema供断言验证 Agent 实际传给模型的参数配合generation_span支持追踪启停tracing_enabled参数。SpanProcessorForTests追踪替身tests/testing_processor.py 定义了线程安全的SpanProcessorForTests并暴露一组断言辅助函数fetch_ordered_spans()、fetch_traces()、assert_no_spans()、assert_no_traces()以及fetch_normalized_spans()。其中fetch_normalized_spans()会剥离 span/trace 的 ID、时间戳等不稳定字段可选择性保留生成结构化的 span 树与 inline-snapshot 配合实现对追踪导出结果的精确比对——这正是 tests/tracing 目录下大量快照用例的底层支撑。配套质量保障命令虽然tests/README.md只提及测试命令但 Makefile 将测试置于完整的质量门禁体系中便于你在本地复现 CI 检查命令作用底层实现make lintruff 静态检查uv run ruff checkMakefilemake formatruff 格式化并自动修复uv run ruff format uv run ruff check --fixMakefilemake mypy全项目严格类型检查uv run mypy .mypy 配置为strict trueMakefile、pyproject.tomlmake coverage覆盖率统计与门禁coverage run -m pytest后生成 XML 并报告--fail-under95要求95% 覆盖率否则失败Makefilemake old_version_testsPython 3.9 兼容性回归使用独立环境.venv_39运行整套测试Makefile覆盖率统计范围限定在tests与src/cai/sdk/agentspyproject.toml且报告会排除if TYPE_CHECKING:、abc.abstractmethod等纯类型检查路径pyproject.toml保证覆盖率指标真实反映可执行代码。小结CAI 框架的测试体系以一条命令跑全量、快照自动维护、真实模型强隔离为设计核心make sync建立可复现的 uv 环境make tests借助 pyproject.toml 的 pytest 配置驱动全量用例inline-snapshot 让复杂结构化输出追踪导出、富文本的断言既精确又可一键维护而 tests/conftest.py 的全局 fixtures、tests/fake_model.py 的模型替身共同保证了测试的确定性、速度与零外部依赖。对希望为框架贡献测试或修复快照的开发者从make sync make tests起步结合make snapshots-fix/make snapshots-create即可快速进入工作流在提交前建议再依次执行make lint、make mypy与make coverage通过全部质量门禁。【免费下载链接】caiCybersecurity AI (CAI), the framework for AI Security项目地址: https://gitcode.com/GitHub_Trending/cai3/cai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进