跳转至

测试

测试套件位于 tests/(在 pplx_export 包之外),完全离线运行——所有输入数据随仓库提交于 tests/fixtures/,没有任何测试触碰网络或真实的用户级配置。本页说明如何运行套件、套件结构以及如何新增测试。机制视角(快照回归如何与渲染器的幂等承诺互锁)见测试系统架构;输入数据本身见测试 fixtures

运行测试

uv run pytest tests

pytest 是已声明的开发依赖,uv run 无需额外安装即可使用。可依赖的保证:

  • 零网络——原始 API 抓取随仓库提交;在线代码路径一律通过离线重渲或 tmp_path / monkeypatch 构造来覆盖。
  • 不读真实用户配置——一个 autouse fixture(tests/conftest.py:40-53)加载占位符账户配置(alice / bob,与 config.example.toml 对齐),因此结果绝不依赖真实的 ~/.config
  • ——300+ 用例约一秒跑完;用例数随回归补充持续增长。

实用筛选:

命令 作用
uv run pytest tests 运行整个套件
uv run pytest tests/test_units.py 运行单个文件
uv run pytest tests -k snapshot 只运行名字匹配 snapshot 的测试
uv run pytest tests -x -q 首个失败即停,静默输出

套件结构

套件分为三个家族:

  • 渲染快照测试——test_render_snapshots.py:从 fixture 原始 JSON 经 normalize → parse → render 的全链路回归,与随仓库提交的 golden 快照逐字节比对。覆盖全部五种模式(search / deep-research / computer / council / study)及裁剪缺陷场景。
  • 单元测试——test_units.py 与各专题文件:状态、节流、增量规划、规范化与维护命令的类/函数级行为。
  • 修复回归文件——test_fix_*.py:每个外部评审发现一个文件(N-xx / V3-xx / V4-xx / V5-xx);文件头 docstring 复述该发现,测试钉住修复后的行为。
文件 覆盖
conftest.py 公共 fixture:render_fixture / rendered;占位符用户配置
test_render_snapshots.py 渲染快照回归:五模式全线程 fixtures + 裁剪缺陷场景;与 golden 逐字节比对;dict-repr 残留特征检查
test_units.py BatchState(尾零归一化、过期终态、损坏备份)、Throttle(退避公式/上限/重置)、plan_incrementalAssetDownloader._final_namenormalize_math_delimsTestDetectModeTestSafeFolderTestFetchMissingBlocksTestExternalReviewFixes
test_interruptions.py 中断语义:classify_wf_status 五分类、归属瀑布 ③ 附录、渲染标注、中断登记
test_stub_workflows.py 残桩轮关联:match_stub_workflows(10 秒时间窗、单次消费、锚定排除)、render_wf_item 嵌套渲染递归/去重守卫
test_relations.py relations 图:same_prompt / references / subagent_of 边构造
test_search_mode_backfill.py search-mode-backfill:具体度优先级、保留原值、幂等续跑、索引合并
test_sync_deleted.py sync-deleted 状态机:跨账户候选判定、终态处理
test_answer_variants.py
test_answer_variant_logging.py
answer_variants 检测链与 ANSWER_VARIANT_DETECTED jsonl 日志
test_config_external.py 用户级外置配置:加载优先级、缺文件降级、resolve_cli_account
test_fix_n01…n11_*.py(9 个文件) 第二轮评审回归(N-01..N-12)
test_fix_v301_*.py / test_fix_v305_*.py 第三轮评审回归(V3-01 / V3-05)
test_fix_v4*.py 第四轮评审回归(V4-01..V4-06)
test_fix_v5_review.py 第五轮评审回归(V5-01..V5-10)

快照测试如何复用生产重渲路径

快照测试不含任何重新实现的管线——它直接调用生产渲染器:

  1. render_fixturetests/conftest.py:56-68)把 fixture 的原始 JSON(raw_entries.json / raw_blocks.json / thread.json)复制进临时目录,并调用 rerenderpplx_export/commands/rerender_cmd.py:105)——即 pplx-export re-render 命令在生产中运行的同一函数。
  2. rendered fixture(tests/conftest.py:71-78)是个工厂:rendered("search_demo") 返回 (重渲后的线程目录, fixtures 里的 golden 目录),测试随后逐字节 diff conversation.md 与每个 turns/turn_*.md
  3. 由于 golden 也经同一条离线路径重生成(见测试 fixtures),测试始终用渲染器的最新输出对比已提交产物:任何改变产物字节的渲染层变更都会让套件变红——与重渲的幂等承诺互锁。

除逐字节相等外,test_render_snapshots.py 还钉住了内容不变式:答案绝不是空占位符 (无);dict-repr 残留特征({'type': ... 泄漏进渲染文本)直接判失败。

如何新增测试

  • 现有逻辑的单元测试——向对应的专题文件添加 test_* 函数(或在 test_units.py 中加一个 Test* 类)。使用 tmp_path / monkeypatch;绝不触网,绝不读真实的 ~/.config(占位符配置是 autouse 的)。
  • 缺陷修复的回归——新建 tests/test_fix_<round><nn>_<slug>.py,文件头 docstring 复述发现(旧行为 → 修复后行为),随后钉住修复后的行为。像现有 test_fix_* 文件一样,在 tmp_path 中直接构造原始 JSON。
  • 渲染回归——需要一个 fixture:在 tests/fixtures/ 下新增(或裁剪)一个,用维护工具刷新其 golden(见测试 fixtures),然后要么把目录名加入 test_render_snapshots.pyFULL / SCENARIOS,要么写一个消费 rendered fixture 的专用 test_* 函数做场景级断言。

遵循既有风格:类型标注、from __future__ import annotations,以及与相邻文件一致的双语模块 docstring。

另见