- 人工智能
- AI Agent
- Agent 编排
- 低代码
- AI 技能
- RAG
【免费下载链接】nexent
Nexent 是一个开源智能体SDK和平台,能够将描述流程的自然语言转化为完整的多模态服务 —— 无需编排,无需复杂拖拉拽。基于 MCP 工具生态系统构建,Nexent 提供灵活的模型集成、可扩展的数据处理和强大的知识库管理。我们的目标很简单:将数据、模型和工具整合到一个智能中心中,让任何人都能轻松地将 Nexent 集成到项目中,使日常工作流程更智能、更互联。
本文基于 Nexent 仓库中维护 Legacy UT 套件的 Skill 文档(.agents/skills/nexent-python-tests/SKILL.md),系统讲解test/backend、test/sdk、test/ext_components三个目录下的 Python 单元测试如何组织、如何编写、如何运行:读者可以完整掌握 lookup-site mock 原则、异步测试与 fixture 隔离策略,以及从窄范围验证到全量 runner 的回归执行方案。
一、定位:Legacy UT 套件与 D1-D5 体系的边界
Nexent 仓库中存在两套并行的测试资产,边界必须严格遵守:
| 维度 | Legacy UT(本文主题) | D1-D5 需求驱动体系 |
|---|---|---|
| 覆盖目录 | test/backend、test/sdk、test/ext_components | test/automation/d1~test/automation/d5 |
| 组织方式 | 按实现模块划分的单元测试 | 需求/Bug → Feature → D1-D5 Case 的追踪链 |
| 编号规则 | 不分配正式 D1-D5 Case ID | 使用如CMSR-D1-001的稳定 Case ID |
| 清单登记 | 不加入test/manifests/d1-d5.yaml | 登记于 manifest,并生成 Excel 基线 |
当前test/backend、test/sdk、test/ext_components下共有 500 余个test_*.py文件(约 545 个),全部属于 Legacy UT。仓库中 D1-D5 体系的真实样例如 manifest 文件,其条目带有case_id、contract_hash与implementation等结构化字段——Legacy UT 文件绝不能以这种形式被登记或计入功能基线。新的 D1-D5 工作应使用nexent-test-assetsSkill,而不是改动 Legacy 套件。
这一边界的意义在于:单元测试的隔离性不能替代真实服务的功能验证。Legacy UT 证明的是"代码逻辑在给定 mock 下正确",而线上行为的验收仍属于 D1-D5 自动化与人工验收的职责。
二、测试基建:pytest.ini与conftest.py
在动任何 fixture 或 import 结构之前,Skill 明确要求先检查三个东西:邻近测试文件、test/conftest.py、test/pytest.ini。以下逐一说明它们实际承担的职责。
2.1test/pytest.ini:异步默认与本地专用标记
pytest.ini 全文很短但决定了整个套件的运行语义:
[pytest] # Automatically detect and handle async test functions asyncio_mode = auto # Create a new event loop for each test function to ensure isolation asyncio_default_fixture_loop_scope = function filterwarnings = # Disable all warnings ignore # Custom markers markers = local_only: marks tests that require external resources (API keys, network) and should only run locally (deselect with '-m "not local_only"')三个关键配置:
asyncio_mode = auto:pytest-asyncio 自动识别async def测试函数,无需逐个添加@pytest.mark.asyncio(Skill 中第 5 步提到的该标记仍然适用于显式标注场景)。asyncio_default_fixture_loop_scope = function:每个测试函数创建独立事件循环,保证异步 fixture 之间的隔离。local_onlymarker:标记需要 API key、网络等外部资源的测试,CI 场景可用pytest -m "not local_only"排除。
2.2test/conftest.py:路径注入、包元数据修复与全局 mock
test/conftest.py 是理解整套 Legacy 测试如何"零真实依赖"运行的关键,它做了以下几件事:
1. 双根路径注入(L24-L33)。将backend/与sdk/目录插入sys.path,使测试既能以from backend.xxx import ...导入,也能以from sdk.xxx import ...导入——这正是后文"lookup-site 取决于实际 import 路径"这一原则的基础。
2. 包元数据修复(L36-L77)。许多测试模块会在收集阶段用轻量 stub 替换consts、services等包的sys.modules条目,导致后续真实子模块导入失败。_restore_project_package_metadata()会重建这些包的__path__、__package__与ModuleSpec,并通过pytest_collectstart钩子和一个autousefixture_restore_project_packages在每次收集与每次测试执行前双重修复。这是理解"为什么 conftest 不能随便改"的核心:它维护着 mock 包与真实包之间的脆弱平衡。
3. 可选 SDK stub。当环境未安装xlrd时,注入一个宽容的_XlrdProxy模块(L95-L128),使evaluation_set_excel_utils的.xls解析路径可以正常导入;单测文件内部可替换为更丰富的 fake。
4. 结构化 supabase mock(L205-L268)。backend.utils.auth_utils在模块加载期执行from supabase.lib.client_options import SyncClientOptions。如果测试文件只是简单地把sys.modules['supabase']换成裸MagicMock,该 import 会失败,并连带使所有传递性导入user_service的测试在收集阶段崩溃。install_supabase_mock()因此构造了带lib、lib.client_options、SyncClientOptions属性的包形 mock,配合autousefixture_supabase_mock在每个测试体执行前重装,防御单个测试文件的覆盖。
5. 自建mockerfixture(L171-L192)。Skill 要求使用 pytest-mock 风格,而 conftest 用_MiniMocker实现了兼容 API:mocker.patch/mocker.patch.object/mocker.patch.dict,fixture 结束自动stopall()。
6. 环境默认值。统一把TMP/TMPDIR/TEMP指向仓库内.pytest-tmp(并覆写tempfile.tempdir),同时为 MinIO、Elasticsearch、PostgreSQL 设置setdefault环境变量(如MINIO_ENDPOINT=http://localhost:9000、POSTGRES_DB=test_db),保证测试不会意外触碰真实服务配置。
此外,test/common/test_mocks.py 提供bootstrap_test_env()(lru_cache的会话级环境自举)与setup_common_mocks()等共享工具,避免各测试文件重复编写数据库/存储 mock。
三、编写测试的七步工作流
以下逐条对应 Skill 文档的七个步骤,并结合仓库中的真实用例说明执行方式。
步骤 1:先确定被测单元与行为,再检查基建
改 fixture 或 import 结构之前,先看邻近测试文件如何组织,再读test/conftest.py与test/pytest.ini。例如要测backend.services.a2a_client_service,可参考同目录的 test_a2a_client_service.py:它按行为拆成TestA2AClientServiceExceptions、TestA2AClientServiceInit、TestExtractAgentUrl等多个类,import 放在各测试方法内部,最大限度规避模块加载期的全局副作用。
步骤 2:命名与文件组织约束
- 只用 pytest:pytest 断言、fixtures、
pytest-mock风格 mock; - 文件与函数以
test_开头,测试类以Test开头; - 单文件控制在 500 行以内,超限时按功能拆分为
test_<module>_<feature>.py; - 拆分产生的包目录必须包含
__init__.py(test/backend、test/sdk各级目录均已如此)。
仓库中的真实案例:test/backend/agents/下同时存在test_create_agent_info.py(数千行,历史主文件)与test_create_agent_info_workbench_coverage.py——后者就是按功能拆分出来的配套文件。
步骤 3:mock 协作方,且必须 patch"查找点"
这是整套规范中最容易被违反的一条:mock 的对象是协作方(collaborator),绝不真正调用外部接口、客户端或服务;patch 的目标必须是"完全限定的查找点"——即被测试模块实际 import 该名字的位置,而不是依赖的定义模块。
Skill 给出的示例:若backend.services.example_service通过from provider import fetch引入fetch,则应 patchbackend.services.example_service.fetch;若运行时该模块实际以services.example_service加载,就使用那条真实路径。切忌从无关示例中照抄路径。
仓库中的实践印证了这一原则。test_config_sync_service.py 开头即注释说明"在导入 backend 之前 patch boto3 及其他依赖",并选择在 botocore 的查找点下手:
# This prevents real AWS/MinIO/Elasticsearch calls during import patch('botocore.client.BaseClient._make_api_call', return_value={}).start() patch('nexent.storage.storage_client_factory.create_storage_client_from_config', return_value=storage_client_mock).start()它同时展示了另一种手段:对database.client等模块直接用types.ModuleType构造 stub 写入sys.modules,再手动维护包属性链接(database_package上挂回client)。两种手段(运行时 patch 与sys.modules预置 stub)都遵循同一准则:让被 import 的名字指向 mock。
步骤 4:隔离外部 I/O,用 fixture 复位可变状态
- 用 fixture 重置可变状态;当作用域内每个测试都需要该重置时,标记
autouse=True——conftest 中的_restore_project_packages、_supabase_mock就是标准示范; - 不要 mock 掉被测行为本身。判断标准:断言所观察的行为如果依赖某个 mock 的返回值,说明 mock 过界了。
步骤 5:成功/错误流、边界与异步
对变更后的成功流、错误流和边界条件写具体、可观察的断言:
- 协作方抛错用
side_effect。真实用例见 test_memory_transparent_proxy.py:
hook = AsyncMock(side_effect=RuntimeError("hook failed"))- 参数变体用
@pytest.mark.parametrize。如 test_create_agent_info.py 中对多分支场景的批量展开; - 异步测试在
asyncio_mode = auto下可直接写async def,需要显式标注时再加@pytest.mark.asyncio; - 异步协作方必须使用 awaitable mock(
AsyncMock)。例如 test_create_agent_info.py 中:
initialize_tools_on_startup=AsyncMock(),若用MagicMock代替AsyncMock,await mock()会直接报错或语义失真。
步骤 6:导入顺序与注释语言
import 按"标准库 → 第三方 → 项目"分组;注释与 docstring 一律使用英文(仓库现有测试文件均遵循,如test_a2a_client_service.py中 "Test class for A2A Client Service exceptions." 的 docstring 风格)。
步骤 7:先窄后宽地运行
Skill 要求从仓库根目录、在可用的 backend 环境下先跑窄范围测试,例如文档给出的命令形态:
pytest test/backend/apps/test_agent_app.py -v当前test/backend/apps/目录中实际存在的文件为test_memory_record_app.py、test_memory_provider_app.py、test_memory_dreaming_app.py,可按同一形态选取真实存在的文件执行(如pytest test/backend/apps/test_memory_record_app.py -v)。必要时可叠加-m "not local_only"排除依赖外部资源的用例。
范围扩大后,全量回归使用仓库既有 runner:
python test/run_all_test.pyrun_all_test.py 的实现比"简单跑一遍 pytest"复杂得多,值得了解其行为:
- 目标目录:默认收集
test/backend、test/sdk、test/ext_components下所有test_*.py; - 环境变量:
NEXENT_PYTEST_WORKERS(并发文件数,默认auto取 CPU 数与文件数的较小值,可设具体数字或off)、NEXENT_PYTEST_FILE_TIMEOUT(单文件超时,默认 600 秒,超时按 returncode 124 记失败)、NEXENT_PYTEST_TARGETS(空格分隔,限定本次运行的目录/文件); - 前置检查:缺失
pytest-cov、coverage、pytest-asyncio时直接报错退出; - 按文件执行:每个文件以独立子进程运行
python -m pytest <file> -q --cov=backend --cov=sdk --cov-branch --disable-warnings,coverage 数据写入.coverage.<index>; - 结果聚合:解析各文件
N passed / M failed摘要,输出 Pass Rate,失败文件附带 short summary 与截断的输出;最后coverage combine合并并生成coverage_html/、coverage.xml报告,任一文件失败或 coverage 失败则进程返回非零。
四、结果汇报与验证边界
工作流的收尾要求:如实报告执行过的命令、结果与环境故障(如缺包、端口不可达)。Skill 特别强调:单元测试的隔离性不替代 live-service 功能检查与真实模型验收——Legacy UT 通过只证明实现层逻辑,端到端行为仍需 D1-D5 自动化套件或人工验收覆盖。
五、要点速查
| 实践点 | 规则 | 仓库依据 |
|---|---|---|
| 套件边界 | 不分配 D1-D5 ID、不入 manifest、不计入基线 | manifest 示例 |
| 异步默认 | asyncio_mode = auto,每测试独立事件循环 | pytest.ini |
| mock 目标 | patch 查找点而非定义模块 | config_sync 测试 |
| 异步 mock | 协作方必须AsyncMock | 用例 |
| 文件规模 | <500 行,超限按test_<module>_<feature>.py拆分 | test/backend/agents/目录结构 |
| 本地专用用例 | -m "not local_only"排除 | pytest.ini |
| 全量回归 | python test/run_all_test.py,支持 workers/timeout/targets 三个环境变量 | runner |
遵循这套规范,新增或修复的单元测试既能通过 CI 的窄范围验证,也能安全地并入run_all_test.py的全量回归与覆盖率统计,同时与 D1-D5 正式测试资产体系保持清晰边界。
- 人工智能
- AI Agent
- Agent 编排
- 低代码
- AI 技能
- RAG
【免费下载链接】nexent
Nexent 是一个开源智能体SDK和平台,能够将描述流程的自然语言转化为完整的多模态服务 —— 无需编排,无需复杂拖拉拽。基于 MCP 工具生态系统构建,Nexent 提供灵活的模型集成、可扩展的数据处理和强大的知识库管理。我们的目标很简单:将数据、模型和工具整合到一个智能中心中,让任何人都能轻松地将 Nexent 集成到项目中,使日常工作流程更智能、更互联。
相关推荐
Flet 单元测试实战:用 uv 与 pytest 运行 Python SDK 测试套件
Flet 单元测试实战:用 uv 与 pytest 运行 Python SDK 测试套件 本指南聚焦 Flet 开源仓库中 Python 框架部分的单元测试体系
前端跨平台桌面应用移动开发django-oscar 测试套件运行指南:pytest 工作流、tox 多版本矩阵与测试目录规范
django oscar 测试套件运行指南:pytest 工作流、tox 多版本矩阵与测试目录规范 本文是 django oscar(基于 Django 的领域
后端电商Open3D Python 单元测试指南:基于 pytest 的安装、运行与测试套件深度解析
Open3D Python 单元测试指南:基于 pytest 的安装、运行与测试套件深度解析 导读 本文以 python/test/readme.md http
计算机视觉图形学3D渲染科学计算
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考