基于代码图的变异测试结果分选工具。先通过 Trailmark 解析代码库,执行变异测试与 necessist,再结合存活变异体(survived mutants)、冗余测试语句及调用图数据,精准识别误报、测试覆盖缺失和 Fuzzing 目标。适用于对存活变异体进行分类排查、分析变异测试结果、定位测试盲区、基于弱测试寻找 Fuzzing 目标、运行变异框架(包含 circomvent 和 cairo-mutants)或使用 necessist 的场景。
Genotoxic
将变异测试(Mutation testing)和 necessist(测试语句裁减)与代码图分析相结合,对发现的问题进行分类排查(Triage),将其归类为可落地的具体分类:误报(False positives)、缺失的单元测试以及 Fuzzing 目标。
适用场景
- 变异测试跑出存活变异体(survived mutants),需要进一步分类排查时
- 寻找编写单元测试收益最高的核心代码位置时
- 寻找更适合写 Fuzz harness 而非普通单元测试的函数时
- 利用数据流上下文评估并优化测试优先级时
- 从变异结果中过滤无害变异体,筛选出真正需要处理的问题时
- 查找测试中多余/无效的语句(necessist),定位弱断言测试时
不适用场景
- 代码库完全没有现有测试套件(请先编写基础测试)
- 纯文档修改或纯配置变更
- 逻辑极其简单的单文件脚本
前置条件
- 已安装 trailmark — 如果
uv run trailmark运行失败,请执行:
切勿以“手动验证”或“手动分析”替代运行 trailmark。必须优先安装该工具;若安装失败,请直接报错反馈,严禁切到手动分析模式。uv pip install trailmark - 目标语言对应的变异测试框架 — 若框架命令运行失败(如未找到或未安装),请按照 references/mutation-frameworks.md 中的指引进行安装。切勿退回到“手动变异分析”或直接跳过变异测试。必须先完成框架安装;若安装失败,请报出错误,而不是转入手动变异分析。
- necessist(可选,推荐)— 如果目标语言受支持(Go、Rust、Solidity/Foundry、TypeScript/Hardhat、TypeScript/Vitest、Rust/Anchor),可以通过
cargo install necessist安装。详见 references/mutation-frameworks.md。 - 一套可正常通过的现有测试套件
- macOS 环境注意:在调用
mull-runner之前,必须先运行ulimit -n 1024。macOS Tahoe (26+) 默认会将文件描述符设为无限制(unlimited),这会导致 Mull 在创建子进程时崩溃。详见 references/mutation-frameworks.md。
拒绝摆烂借口
| 错误借口 / 托词 | 错在哪 | 必须采取的行动 |
|---|---|---|
| “所有存活的变异体都需要写测试” | 很多变异体是无害的或等价变异(Equivalent mutant) | 写测试前先进行分选(Triage) |
| “变异测试噪声太大了” | 觉得噪声大说明你没有做分选 | 利用代码图数据进行过滤 |
| “单元测试已经全覆盖了” | 复杂的数据流需要 Fuzzing | 检查入口点的可达性(Reachability) |
| “死代码里的变异体不用管” | 死代码本身就应该清理掉 | 标记出来并进行清理 |
| “复杂度低 = 风险低” | 边界 Bug 往往藏在看似简单的代码里 | 检查变异体所在具体位置 |
| “工具没装,我手动分析吧” | 手工分析必然会漏掉自动化工具能捕获的问题 | 必须先安装工具 |
| “Necessist 不是变异测试,跳过它” | Necessist 能找出变异测试漏掉的问题:弱测试(Weak tests) | 只要语言支持,就必须两者都运行 |
快速上手
# 1. 构建代码图
uv run trailmark analyze --language auto --summary {targetDir}
# 2. 运行变异测试(因语言而异)
# Python:
uv run mutmut run --paths-to-mutate {targetDir}/src
uv run mutmut results
# 2b. 运行 necessist(若语言支持)
necessist
# 3. 使用本 Skill 的工作流分析结果(阶段 3)
工作流概览
阶段 1: 图构建 → 使用 trailmark 解析代码库
↓
阶段 2: 变异测试运行 → 执行变异测试框架
阶段 2b: Necessist 运行 → 裁减测试语句(可选,可并行)
↓
阶段 3: 分选 (Triage) → 结合图数据对结果分类
↓
输出:分类报告
├── 相互印证 (Corroborated) (两个工具标记同一函数 —— 价值最高)
├── 误报 (False Positives) (无害,跳过)
├── 缺失测试 (Missing Tests)(编写单元测试)
└── Fuzzing 目标 (搭建 Fuzz harness)
决策树
├─ 需要为某种语言配置变异测试?
│ └─ 请参阅:references/mutation-frameworks.md
│
├─ 需要配置 necessist 或查找弱测试语句?
│ └─ 请参阅:references/mutation-frameworks.md(Necessist 章节)
│
├─ 需要深入理解分选(Triage)的标准?
│ └─ 请参阅:references/triage-methodology.md
│
├─ 需要了解图数据如何辅助分选?
│ └─ 请参阅:references/graph-analysis.md
│
└─ 已经拿到结果 + 图数据?直接执行下文的阶段 3。
阶段 1:构建代码图并运行预分析
在执行变异测试之前,先使用 trailmark 解析目标代码库并运行预分析(Pre-analysis)。预分析会计算爆炸半径(Blast radius)、入口点(Entry points)、特权边界(Privilege boundaries)以及污染传播(Taint propagation),这些数据将在阶段 3 的分选排查中使用。
uv run trailmark analyze --language auto --summary {targetDir}
使用 QueryEngine API 构建图结构并运行预分析:
QueryEngine.from_directory("{targetDir}", language="auto")- 调用
engine.preanalysis()— 分选前必须执行 - 通过
engine.to_json()导出数据,以便与变异测试结果进行交叉比对
如果自动识别的目标语言有误,可以传入明确的语言名称或逗号分隔列表重新运行(例如 python,rust)。
完整的 API 细节(包含节点映射、可达性查询、爆炸半径及预分析子图检索),请参阅 references/graph-analysis.md。
阶段 2:运行变异测试
选择并运行合适的变异测试框架。针对具体语言的安装配置,请参阅 references/mutation-frameworks.md。
收集存活的变异体(Survived mutants)。 不同框架的报告格式可能不同,但针对每个变异体,需提取以下字段:
| 字段 | 描述 |
|---|---|
| File path(文件路径) | 包含该变异体的源文件路径 |
| Line number(行号) | 应用变异的具体行号 |
| Mutation type(变异类型) | 被修改的内容(如运算符、数值等) |
| Status(状态) | survived(存活)、killed(被杀)、timeout(超时)、error(错误) |
仅筛选出**存活(survived)**的变异体,用于阶段 3 的分选。
阶段 2b:运行 Necessist(可选)
如果目标语言受支持(Go、Rust、Solidity/Foundry、TypeScript/Hardhat、TypeScript/Vitest、Rust/Anchor),运行 necessist 找出多余的测试语句。此步骤独立于阶段 2,可并行执行。
# 自动检测框架
necessist
# 或指定特定的测试文件
necessist tests/test_parser.rs
# 导出结果
necessist --dump
筛选出**删改后测试依然通过(passed after removal)**的结果。具体的框架配置及标准规范记录格式,请参阅 references/mutation-frameworks.md。
利用 references/graph-analysis.md 中的算法,将每次删改映射到对应的生产函数(Production function)。
阶段 3:分选结果 (Triage Findings)
结合代码图数据,为每个存活变异体及 necessist 裁减项确定其归属的分选桶(Bucket)。 necessist 裁减项必须先映射到生产函数(详见 references/graph-analysis.md)。
快速分类规则(变异测试)
| 信号/特征 | 分选桶 | 判决依据 |
|---|---|---|
| 图结构中无调用方 | 误报 (False Positive) | 死代码,变异体不可达 |
| 仅有测试代码调用 | 误报 (False Positive) | 测试基础设施代码,非生产逻辑 |
| 日志/展示字符串变异 | 误报 (False Positive) | 仅影响 UI/展示,不影响核心行为 |
| 等价变异体 (Equivalent mutant) | 误报 (False Positive) | 变异后实际运行行为未发生变化 |
| 简单函数、圈复杂度(CC)低、无入口点路径 | 缺失测试 (Missing Tests) | 编写单元测试直截了当 |
| 错误处理路径 | 缺失测试 (Missing Tests) | 应补充反向/异常测试用例 |
| 边界条件(如 off-by-one) | 缺失测试 (Missing Tests) | 适合采用属性测试(Property-based test) |
| 纯函数、结果确定 | 缺失测试 (Missing Tests) | 易于测试,收益高 |
| 高圈复杂度 CC (>10),且入口点可达 | Fuzzing 目标 (Fuzzing Target) | 复杂度高 + 暴露在外 = 极适合 Fuzzing |
| 解析器/验证器/反序列化组件 | Fuzzing 目标 (Fuzzing Target) | 专门处理结构化输入 |
| 被大量调用 (>10) + 中等圈复杂度 CC | Fuzzing 目标 (Fuzzing Target) | 爆炸半径(Blast radius)大 |
| 二进制/网络协议处理逻辑 | Fuzzing 目标 (Fuzzing Target) | Fuzz 工具非常擅长测试这类格式 |
快速分类规则(Necessist)
| 信号/特征 | 分选桶 | 判决依据 |
|---|---|---|
| 冗余的初始化或调试调用 | 误报 (False Positive) | 语句本身确实没有实质作用 |
| 无法映射到生产函数 | 误报 (False Positive) | 缺乏图数据上下文,无法进一步分选 |
| 函数调用被删除,但没有断言对其效果做检验 | 缺失测试 (Missing Tests) | 测试断言力度较弱 |
| 断言被删除,测试依然成功通过 | 缺失测试 (Missing Tests) | 断言冗余或测试覆盖不足 |
| 映射到高 CC 且入口点可达的函数 | Fuzzing 目标 (Fuzzing Target) | 逻辑复杂 + 接口暴露 + 现有测试弱 |
当变异测试与 necessist 同时标记了同一个生产函数时,将其标记为相互印证(corroborated) —— 这是可信度最高的高价值发现。
详细判决标准,请参阅 references/triage-methodology.md。
用于分选的图查询
针对每一个变异体,将其映射到对应的图节点,并使用阶段 1 生成的预分析子图数据(tainted、high_blast_radius、privilege_boundary)进行分类。分类逻辑的检查顺序为:无调用方 → 误报(false positive);特权边界 → Fuzzing 目标;高圈复杂度 CC + 被污染数据流 → Fuzzing 目标;大爆炸半径 → Fuzzing 目标;其他情况 → 缺失测试(missing tests)。
有关 batch_triage 的实现细节和节点映射函数,请参阅 references/graph-analysis.md。
输出格式
生成 Markdown 格式的报告:
# Genotoxic 分选报告
## 概览
- 存活变异体总数:N
- Necessist 裁减语句总数:N
- 相互印证的发现数:N
- 误报数量:N (N%)
- 测试覆盖缺失数:N (N%)
- Fuzzing 目标数:N (N%)
## 相互印证的发现 (Corroborated Findings)
| 文件 | 行号 | 函数 | 变异测试信号 | Necessist 信号 | 建议操作 |
|------|------|----------|----------------|------------------|--------|
## 误报 (False Positives)
| 文件 | 行号 | 变异内容 | 判定原因 | 来源 |
|------|------|----------|--------|--------|
## 缺失测试覆盖 (Missing Test Coverage)
| 文件 | 行号 | 函数 | CC (圈复杂度) | 调用方数量 | 建议测试类型 | 来源 |
|------|------|----------|----|---------|----------------|--------|
## Fuzzing 目标 (Fuzzing Targets)
| 文件 | 行号 | 函数 | CC (圈复杂度) | 入口点路径 | 爆炸半径 | 来源 |
|------|------|----------|----|-----------------|--------------|--------|
来源 列填写 mutation、necessist 或 corroborated。
将报告写入当前工作目录下的 GENOTOXIC_REPORT.md 文件中。
质量检查清单
交付前请确认:
- [ ] 已针对目标语言构建 Trailmark 代码图
- [ ] 变异测试框架已完整运行结束
- [ ] 已运行 Necessist(若语言支持),或已注明不适用
- [ ] 所有存活变异体均已完成分选(无未分类项)
- [ ] 所有 Necessist 裁减项均已完成分选(若适用)
- [ ] 已标出相互印证的发现(若两个工具均运行)
- [ ] 所有误报项均有清晰合理的理由
- [ ] 缺失测试项均给出了建议的测试类型
- [ ] Fuzzing 目标包含具体的入口点路径及爆炸半径
- [ ] 报告文件已写入
GENOTOXIC_REPORT.md - [ ] 已将汇总统计数据通知用户
与其他 Skill 的集成
trailmark skill:
- 阶段 1:构建代码图,查询圈复杂度与入口点
- 阶段 3:调用方分析、可达性分析、爆炸半径计算
property-based-testing skill:
- 涉及边界条件的测试覆盖缺失项
- 针对序列化变异体的往返/幂等性属性测试(Roundtrip/idempotence properties)
testing-handbook-skills (fuzzing):
- Fuzzi
<!-- truncated for translation batch; full body continues in source -->






