Skip to main content
Glama

testgen-agent

testgen-agent 是一个自动为 Python 代码生成单元测试的工具。它读取源码、生成 pytest 测试、在隔离沙盒中真实运行,并根据运行结果自我修正,直到覆盖率达到设定门槛。

区别于只生成测试代码的工具,它还会用变异测试验证生成的测试是否真正有效,并据此识别源码中的潜在 bug。生成过程被封装为一个 LangGraph 自主循环,可通过命令行使用,也可作为 MCP 工具集成到其他 Agent 工作流中。

主要特性

  • 自动生成与修正:生成测试后真实运行,失败时读取报错堆栈自动重写,无需人工介入。

  • 测试有效性验证:通过变异测试(对源码做微小改动后重跑)判断测试是否真正覆盖了逻辑,而非仅仅提高覆盖率数字。

  • 源码 bug 识别:当一条测试在原始源码上失败、却能在某个变异体上通过时,判定为疑似源码 bug 并上报。

  • 沙盒隔离与防篡改:源码在沙盒中只读,运行前后做哈希校验,确保测试结果不被源码改动干扰。

  • 人工审核:仅在出现疑似源码 bug 时暂停,交由使用者确认,其余情况全自动完成。

  • 可复现:未配置模型 API key 时使用内置确定性生成器,闭环仍可完整运行。

Related MCP server: mcp-lab-agent

工作原理

所有判定都建立在真实运行的结构化结果之上:pytestcoverage 给出退出码、失败堆栈与覆盖率,变异测试给出测试有效性信号,工具据此做出确定性决策。

运作流程(LangGraph 6 节点自主循环)

                    +-----------------------------------------------+
                    |            State(全程共享的状态字典)          |
                    |  source_code / functions / source_hash        |
                    |  generated_test_code / last_run / mutation    |
                    |  coverage_before / coverage_after             |
                    |  attempt / suspected_bugs / review_decisions  |
                    +-----------------------------------------------+

  [START]
     |
     v
 +--------------+
 | (1) analyze  |  ast 解析源码:提取函数签名、分支提示、源码哈希
 +------+-------+
        |  产出"考纲"(该覆盖哪些分支)+ 防篡改用的 hash
        v
 +--------------+
 | (2) generate |  LLM 按源码+考纲+上轮失败 写/修测试         <----------+
 +------+-------+  (无 API key 时用内置确定性启发式生成器)             |
        |                                                                |
        v                                                                |
 +--------------+                                                        |
 | (3)(4)       |  sandbox:复刻项目、源码设只读、写入测试               |
 |   execute    |  run   :subprocess 跑真实 pytest --cov,读退出码/覆盖率|
 |              |  mutate:逐个变异源码重跑,统计杀伤 + 收集 bug 证据    |
 +------+-------+                                                        |
        |  产出结构化事实:last_run / mutation / source_tampered         |
        v                                                                |
 +--------------+                                                        |
 | (5) evaluate |  防作弊校验 + 覆盖率门禁 + 失败归因                     |
 +------+-------+                                                        |
        |                                                                |
        v                                                                |
   < decision 路由 >                                                     |
    |-- retry  --> 回 (2) generate,带着失败堆栈重写 --------------------+
    |
    |-- review --> +--------------+   interrupt 暂停,把疑似 bug 交给人
    |              | (H) review   |   人选 confirm_bug / ignore 后
    |              +------+-------+   Command(resume=...) 从断点续跑
    |                     |          回到 (5) evaluate 复判
    |                     +--------> (5) evaluate
    |
    |-- done   --> +--------------+
                   | (6) report   |  汇总量化指标 + 生成报告
                   +------+-------+
                          |
                       [END]

条件边 evaluate -> generate 就是"循环"的来源,也是它作为 Agent 的本质。人工审核用 LangGraph 的 interrupt 实现,依赖 checkpointer 支持断点续跑。

每个节点做什么、为什么技术上成立

节点

输入

做的事

为什么能实现

① analyze

源文件

ast.parse 提取函数签名、if/循环/比较分支,算源码哈希

ast 是标准库,语法树遍历是确定性的,无需模型

② generate

源码 + 分支考纲 + 上轮失败堆栈

调 LLM 写/修测试;无密钥时用启发式生成器

tool-calling;报错来自真实运行,模型据此修正而非猜

③ sandbox

源码 + 生成的测试

临时目录复刻项目,源码只读,运行前后哈希校验

文件系统隔离 + hashlib 防止偷改源码作弊

④ run_tests

沙盒目录

subprocesspytest --cov,解析退出码/失败堆栈/覆盖率

pytest + coverage 产出结构化事实,程序读事实

⑤ evaluate

运行结果 + 变异结果

门禁判定 + 失败归因(测试写错 vs 源码 bug)

变异测试给确定性信号,判定是纯 if 逻辑

⑥ report

全程指标

汇总覆盖率变化/采纳丢弃/变异杀伤/确认 bug

指标全部来自真实运行,非估算

快速开始

pip install -r requirements.txt
pip install -e .

# 对内置示例(含一个真实 bug)跑一遍,非交互模式自动确认疑似 bug
python -m testgen_agent.cli run \
    --source examples/src/calc.py \
    --test examples/tests/test_calc.py \
    --target 80 --assume confirm_bug

设置 OPENAI_API_KEY 后自动改用真实模型生成测试;未设置时使用内置确定性启发式生成器,闭环照常运行、可复现。

运行示例输出

----------------------------------------------------
 源文件      examples/src/calc.py
 覆盖率      66.67%  ->  88.89%  (+22.22)
 采纳/丢弃   3  /  0
 迭代轮数    1
 变异杀伤    3/4
 确认真bug   1
    - tests/test_generated.py::test_bound_in_range: assert False is True (in_range(10,1,10) 上界漏判)
 门禁        PASS
----------------------------------------------------

人工审核(human-in-the-loop)

只有当变异验证判定"疑似源码 bug"时,图才会通过 interrupt 暂停,把疑点交给人:

[human-in-loop] 发现疑似源码 bug,暂停等待确认
  用例   tests/test_generated.py::test_bound_in_range
  信息   assert False is True (in_range(10,1,10))
  证据   断言失败且变异验证显示测试描述了正确行为
  [k] 确认是bug  [i] 忽略  >
  • k(confirm_bug):标记为真实 bug 上报,保留该测试。

  • i(ignore):当作测试期望有误,丢弃。

普通失败(如测试自身 ImportError/SyntaxError)不会打扰人,直接丢弃重写。

作为 MCP 工具供 Codex / Claude 调用

pip install mcp
python -m testgen_agent.mcp_server

工具 generate_verified_tests(source_path, test_path, coverage_target, ...) 返回与命令行一致的量化报告。集成到其他 Agent 工作流时,上层 Agent 决定对哪个文件生成测试,本工具负责生成、验证并返回结果;疑似 bug 的信息通过返回值交回上层 Agent,由其转达使用者。

项目结构

testgen_agent/
  analyze.py     ① ast 静态分析
  generate.py    ② 生成/修正测试(LLM 或启发式)
  sandbox.py     ③ 沙盒隔离 + 防篡改哈希校验
  runner.py      ④ 跑 pytest,解析结构化结果
  mutate.py      变异测试:验证测试有效性 + bug 归因证据
  execute.py     ③④ 组合节点:沙盒→运行→变异
  evaluate.py    ⑤ 门禁判定 + 失败归因(纯函数,可在审核后重入)
  review.py      人工审核(interrupt)
  report.py      ⑥ 汇总量化报告
  graph.py       LangGraph 组装 6 节点自主循环
  cli.py         命令行入口
  mcp_server.py  MCP 工具封装
examples/        含一个内置真实 bug 的示例项目
tests/           本项目自身的单元与端到端测试

测试

pytest tests -q            # 全部(含端到端)
pytest tests -m "not slow" # 仅快速单元测试

设计边界与后续

当前 MVP 聚焦单文件、Python、比较类变异算子,命令行运行。已规划但未纳入 MVP:多语言、Docker 级沙盒、更多变异算子、Web 可视化报告。这些不影响核心闭环的可量化与可复现。

License

MIT

Related MCP Connectors

Related MCP Servers