☰
Understand-Anything tested_by测试覆盖链接机制揭秘:两遍归一化如何规范测试边
2026/10/11 4:59:49 网站建设 项目流程

Understand-Anything tested_by测试覆盖链接机制揭秘:两遍归一化如何规范测试边

【免费下载链接】Understand-AnythingGraphs that teach > graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.项目地址: https://gitcode.com/GitHub_Trending/un/Understand-Anything

Understand-Anything 能把任意代码仓库变成可探索、可搜索、可提问的交互式知识图谱,而图谱质量的关键一环,就是tested_by 测试覆盖链接机制:在合并分析批次的merge-batch-graphs.py中,一个确定性的"两遍归一化"链接器(linker)会把散落在各批次里的测试边统一规范为production → test方向,让知识图谱里的测试覆盖关系清晰、可审计、不会重复。本文面向新手,带你看懂这套机制的工作原理。

一、问题背景:LLM 生成的测试边为什么会"乱"

在/understand技能的多智能体流水线中,文件分析智能体会把每个批次的分析结果写成batch-*.json,其中包含节点(文件、函数、类)和边(imports、calls、tested_by等关系类型,完整枚举见 schema.ts)。

其中tested_by表示"某生产代码文件被某个测试文件覆盖"。但 LLM 生成的这类边有三个通病:

通病原因
方向系统性反了LLM 只有在分析测试文件时才会看到import 生产代码的关系,于是它习惯把测试文件写在 source 一侧(test → production)
出现无意义的边test↔test、production↔production、端点节点缺失的"孤儿边"
覆盖不全很多测试文件根本没被 LLM 关联到任何生产文件

简单地把这些边"删掉重算"会丢掉 LLM 真实看到的配对证据(比如一个 Go 的_test.go覆盖同包多个.go文件)。Understand-Anything 的方案是:保留配对证据,纠正方向,补齐遗漏——这正是两遍归一化的核心思想(见 SKILL.md 的说明)。

二、第一遍:保留 LLM 语义,纠正方向(Pass 1)

核心逻辑位于 merge-batch-graphs.py 的link_tests函数中。Pass 1 遍历所有type == "tested_by"的边,对每条边按端点分类做三选一处理:

  1. 方向正确(production → test):原样保留;
  2. 方向反了(test → production):原地交换 source/target,把方向纠正为forward,并在 description 中追加[direction corrected]审计标记——配对证据被完整保留,只是方向修正了;
  3. 语义损坏(test↔test、prod↔prod、端点缺失):直接丢弃,因为已无可恢复的含义。

此外还有两个工程细节:

  • 权重感知去重:同一对 (production, test) 出现多条边时,保留 weight 更大的那条(规则与后续 Step 6 的边去重保持一致),避免低置信度边"占位";
  • tested标签:凡是最终成为某条tested_by边 source 侧的生产文件节点,都会被打上"tested"标签,方便在面板里一眼看出哪些代码有测试覆盖。

三、第二遍:按路径约定补齐遗漏(Pass 2)

Pass 1 之后,还有一些测试文件没有被任何边覆盖。Pass 2 就登场了:对每个未配对的测试文件,调用 production_candidates 按各语言的路径约定生成候选生产文件路径列表,取第一个在图中真实存在的候选,生成一条新的production → test边(weight 0.5,description 标记为 "Path-based pairing (deterministic)")。

候选规则覆盖了主流语言布局,配置集中在文件顶部的 tested_by linker 配置区:

  • JS/TS 系:foo.test.ts→ 同目录foo.ts/tsx/js/...;支持__tests__/、test/、spec/子目录"走出"匹配;支持tests/foo/X.test.ts→src|app|lib|根目录/foo/X.ts的镜像树;
  • Go:foo_test.go→ 同目录foo.go;
  • Python:test_bar.py/bar_test.py→ 同目录或镜像树bar.py,支持 Django 式mypkg/tests/布局;
  • Java/Kotlin:Maven/Gradle 布局src/test/java/...→src/main/java/...;
  • C#:支持<svc>/tests/→<svc>/src/以及My.App.Tests/→My.App/的镜像项目;
  • Swift/Rust/PHP:tests/目录内的文件一律视为测试源。

判断"某个路径是否算测试文件"由 is_test_path 统一完成——注意 JS/TS 系要求文件名必须带.test/.spec中缀,所以__tests__/helpers.ts这种工具文件不会被误判成测试。

四、结果在哪里看:合并报告自审计

整个链接器在merge_and_normalize的Step 5b阶段运行(位于节点去重之后、边去重之前),并在合并报告中输出独立小节:

  • Fixed区统计"翻转了多少条测试边、丢弃了多少条损坏边";
  • Tested-by linker区统计"新增了多少条路径约定边、给多少生产节点打上 tested 标签"。

这样每次合并都是可审计的:哪些边是 LLM 证据、哪些是确定性规则补齐、哪些被纠正了方向,一目了然。最终产物写入<ua-dir>/intermediate/assembled-graph.json,供后续面板渲染与评审阶段消费。

五、测试覆盖:91 个单元测试守住行为契约

这套机制本身也有完善的测试。test_merge_batch_graphs.py 包含 91 个测试用例,重点验证:

  • IsTestPathTests:13 种语言的测试文件识别与生产文件排除;
  • ProductionCandidatesTests:各语言候选路径的生成顺序与优先级(同目录优先于镜像树);
  • LinkTestsTests:反向边"交换而非删除"、test↔test 与孤儿边丢弃、重复边保留高权重、补齐不重复已有配对、幂等性等;
  • 典型用例 test_inverted_llm_edge_is_swapped_not_stripped 直接演示了src/foo.test.ts → src/foo.ts的反向边被纠正为src/foo.ts → src/foo.test.ts,且 description 中留痕 "direction corrected"。

运行方式:

python -m unittest tests.skill.understand.test_merge_batch_graphs -v

六、小结:为什么"交换"优于"删除重算"

方案优点缺点
删除全部 LLM 测试边,纯路径约定重算规则简单丢失真实项目的非标准配对(如一对多测试覆盖),覆盖率下降
两遍归一化(本项目方案)保留 LLM 真实证据 + 纠正方向 + 补齐遗漏 + 全程留痕可审计规则较多,但均有单测约束

对新手而言,记住一句话即可:tested_by 边最终永远是"生产文件 → 测试文件",方向反的会被翻转、坏掉的会被丢弃、缺掉的会按路径约定补上,而且每一步都会在合并报告里留下数字账目。这也是 Understand-Anything "图谱是用来教你的,不是用来炫技的"这一理念的落地细节。

💡 延伸阅读:SKILL.md 中 Phase 2 合并脚本的完整说明,以及 graph-reviewer.md 中 27 种边类型(含tested_by)的评审约定。

【免费下载链接】Understand-AnythingGraphs that teach > graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.项目地址: https://gitcode.com/GitHub_Trending/un/Understand-Anything

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

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

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

立即咨询