Industry & PracticeResearch & Benchmarks
NeuroTestGen: 用 大 语言 模型 做 神经 符号 引导 的 测试 生成
York 大学论文全译:符号执行(Z3)解数值路径 + LLM 解对象路径的混合测试生成。Defects4J 14 项目上,Claude 3.5 下行覆盖 70.88%→75.87%、分支 65.15%→70.87%,胜过 SOTA Panta。原文 CC BY 4.0。
In this piece
NeuroTestGen:用大语言模型做神经符号引导的测试生成(中文全译)
翻译说明:本文是 arXiv 论文 NeuroTestGen: Neuro-Symbolic Guided Test Generation with Large Language Models(arXiv:2609.30178,2026-09-24 提交)的中文全译,由智测团队翻译。原作者:Ruixin Zhang、Jiho Shin、Hung Viet Pham、Song Wang(York University,加拿大)。原文以 CC BY 4.0 许可发布,允许翻译与再分发,须署名。译文保留原文全部章节、实验数据与结论;参考文献列表与文内引注编号从略,模型名、工具名、基准名、指标名保留英文。图 1(方法总览)随文保留,版权归原作者。原文附录 A、B(失败分析、影响声明)未随 arXiv HTML 提供,从略;其要点已在正文相应处保留。
摘要
确保高结构覆盖率仍是自动化测试生成中的一个根本挑战,尤其对复杂软件系统——要到达特定行或分支需要满足错综的控制流和数据流约束。大语言模型(LLM)近期在产出类人测试用例方面展示了强大能力;然而,它们常常难以生成满足精确路径条件的输入。反过来,符号执行能系统地推导这类约束,但它常无法构造真实、可执行的测试用例,并受可扩展性局限的约束。
本文介绍 NeuroTestGen,一个把符号执行与 LLM 驱动的测试合成整合的混合方法,用于生成瞄准按需代码覆盖率的测试用例。给定一个方法内的一组目标语句,NeuroTestGen 首先用一个符号分析引擎(即 Z3 SMT 求解器)提取路径特定约束,并为期望的覆盖率目标构造一个符号引导规格。然后这个规格被用来引导 LLM 合成既结构有效又语义有意义的具体测试用例。对涉及复杂对象相关约束、SMT 求解器难以处理的路径,NeuroTestGen 利用 LLM 推断合理的约束。此外,NeuroTestGen 纳入一个迭代反馈循环,验证 LLM 生成的测试并提供纠正性引导,直到目标行或分支被覆盖、或达到上限。我们在一个广泛使用的基准上的实证评估表明,NeuroTestGen 在多个 LLM 上显著优于最先进方法,包括 Llama 3.3 70B、GPT-4o Mini、Claude 3.5 Haiku 和 Claude Sonnet 4.6。
1 引言
动机:软件测试仍是揭示现代软件系统缺陷最有效、最广泛使用的方法之一。尽管有数十年研究,自动生成能达到精确结构覆盖率(如到达特定行、分支或路径)的高质量测试,仍是一个根本挑战。传统测试生成技术,如符号执行、基于搜索的测试和混合符号执行(concolic execution),在系统性探索程序行为方面取得了实质进展。然而,这些技术常难以扩展到真实软件,并频繁无法产出开发者能在现有测试套件中轻松采用的可读、可维护测试。
大语言模型(LLM)的近期进展为自动化测试生成打开了新可能。LLM 展示了合成类人单元测试、构造真实输入对象、组合正确 API 序列,以及自然集成到 JUnit 等框架的卓越能力。然而,基于 LLM 的测试生成有一个关键局限:虽然 LLM 擅长生成貌似合理的测试,它们缺乏构造满足特定路径约束的测试所需的精确推理。达成目标分支或行常需要满足错综的控制流和数据流条件、维持对象不变量,或触发特定程序状态——这些是 LLM 单独无法可靠保证的能力。
为解决这一局限,近期方法已尝试把 LLM 与程序分析技术结合。一个最先进方法是 Panta,它整合静态控制流分析和动态覆盖率反馈,以迭代引导 LLM 走向未覆盖的程序路径并改进结构覆盖率。虽然这一混合设计展示了把 LLM 与传统分析技术结合的潜力,它仍过度依赖 LLM 的推理和代码生成能力。在实践中,Panta 直接把未覆盖的执行路径纳入提示,而不判断这些路径是否可行或可满足。结果,LLM 可能反复尝试为不可行路径生成测试,导致 token 预算浪费、冗余生成和不稳定性能。此外,因为 Panta 不在生成前显式解析路径约束、推断具体输入条件,或推理方法签名和对象状态,大量语义推理负担被完全委托给 LLM。这种过度依赖容易混淆模型并导致无效或次优的测试生成,尤其对分支逻辑复杂、输入依赖错综的程序。
相比之下,符号执行在推理到达目标程序行为所需的逻辑条件方面非常有效。给定一个目标行或分支,符号执行能系统地推导路径约束、识别必要的输入条件、检测不可行路径,并揭示所需的 API 调用序列。然而,符号执行单独通常产出低层约束或具体输入值,而非完整、可读、对开发者友好的测试用例。此外,它的实际适用性常受可扩展性挑战限制,包括大型面向对象系统中的路径爆炸和复杂堆推理。
2 问题建模
我们方法的整体工作流如图 1 所示。给定一个项目和一个目标源文件,我们首先提示 LLM 生成一组初始测试用例,为后续分析提供基线。然后我们执行静态代码分析以构造控制流图(CFG),并为每个方法枚举可行的执行路径。接着我们的方法把动态覆盖率反馈与 CFG 派生的路径整合,以识别仍未覆盖的候选路径。我们维护一个路径历史日志,以避免反复选择在多次尝试后始终无法覆盖的路径。
一条未覆盖路径被分为两类:纯数值和对象相关。当一条路径的执行逻辑完全由数值计算组成——如算术运算、取模计算、比较和位操作——且所有分支谓词仅定义在原始数值变量上、不涉及对象状态或外部方法语义时,该路径被视为纯数值。相反,当一条路径的执行依赖对象语义或更高层的程序抽象——包括对象创建和访问、方法调用、库 API 调用、常量/全局对象引用,或复杂字符串操作——该路径被视为对象相关。这两类在符号执行阶段被区别处理,使 NeuroTestGen 能更好地应对数值约束与复杂对象交互各自带来的不同挑战。
2.1 用纯符号执行求解纯数值路径
对纯数值路径,我们采用基于 SMT 的符号执行来精确求解路径约束,而不依赖 LLM 推理。图 2(a) 展示了这样一个案例。在示例中,第 13–15 行的未覆盖分支完全依赖从输入变量 n 派生的数值约束。由于该路径不含对象状态、堆引用或复杂 API 语义,它可以仅用符号推理准确求解。
public static int adjust(int n) {
if (n < 0) { return -1; }
if (n == 2) { return 2; }
n = n | 1;
if (n == 1) { return 2; }
final int rem = n % 3;
if (0 == rem) { n += 2; }
return n;
}图 2(a):方法 adjust() 中一条未覆盖的纯数值路径示例——执行从方法入口开始,绕过前面的 return 分支,到达第 13–15 行的 rem == 0 分支,该分支未被当前测试套件覆盖。
为求解这类路径,我们利用 Z3 SMT 求解器。我们首先提取方法参数,并按其声明类型创建对应的符号变量。在符号执行期间,所选路径被顺序遍历,同时维护一个记录每个程序变量符号值的符号环境。赋值语句更新符号状态,而原始符号输入被保留以用于最终模型构造。对路径上的每个分支条件,我们把谓词翻译成 Z3 兼容的约束。如果执行路径走某条件的 false 分支,谓词在被加入求解器前取反(例如,我们把 if (n < 0) 为 False 翻译成 Not(n < 0) 并加入求解器)。涉及算术运算符、取模运算和位运算的数值表达式被直接编码成 SMT 公式。在图 2(a) 所示示例中,符号执行器累积来自前面分支的约束,最终推导出与第 13 行关联的约束,即 0 == rem,其中 rem = n % 3。求解所得约束系统使求解器能合成驱动执行进入第 14 行未覆盖分支的具体输入值。
为控制求解复杂度并维持效率,我们目前在符号执行期间跳过循环体,因为循环处理通常需要循环展开或不变量推断,两者都会大幅增加约束复杂度和求解开销。收集所选路径上的所有约束后,Z3 检查路径条件的可满足性。如果约束集可满足,我们从生成的模型提取具体输入赋值,并用它们作为后续测试生成的引导。否则,该路径被视为不可行并从当前生成尝试中排除。
2.2 用 LLM 求解对象相关路径
虽然符号执行对求解数值约束有效,它在对象相关路径上变得显著低效。这类路径常依赖无法轻易编码成 SMT 约束的语义知识。图 2(b) 呈现一个对象相关路径的示例。在这个示例中,到达第 13–15 行的未覆盖分支需要同时满足两个语义条件:输入对象 mode 必须引用单例对象 Mode.STRICT,且字符串参数 text 必须满足谓词 text.startsWith("A")。这些条件涉及对象身份比较和字符串 API 语义,仅用传统符号执行难以精确建模。
final class Mode {
static final Mode STRICT = new Mode();
private Mode(){}
}
public static int classify(String text, Mode mode) {
if (text == null) { return -1; }
if (text.trim().isEmpty()) { return 0; }
if (mode == Mode.STRICT && text.startsWith("A")) { return 1; }
return 2;
}图 2(b):方法 classify() 中一条未覆盖的对象相关路径示例——执行到达第 13–15 行依赖对象的分支 mode == Mode.STRICT && text.startsWith("A"),该分支未被当前测试套件覆盖。
为应对这一挑战,我们采用一个基于 LLM 的路径求解策略,使用一个叫 LLM-Path-Solver 的专门组件。给定一条对象相关路径,我们避免把路径翻译成 SMT 约束。相反,我们把路径信息直接提供给 LLM-Path-Solver,包括源代码、方法签名、未覆盖分支条件和执行路径上下文。基于这些信息,模型推理程序语义并合成能驱动执行走向目标分支的具体方法输入。对图 2(b) 所示示例,LLM-Path-Solver 推断第 13 行的分支条件只有在 mode 等于 Mode.STRICT 且输入字符串以字符 "A" 开头时才能满足。相应地,它可能生成一个像 classify("Apple", Mode.STRICT) 的输入,使执行进入未覆盖分支并覆盖第 14 行。
由于 LLM 生成的输入仍可能包含推理错误或语义幻觉,我们进一步引入一个二级验证阶段,使用另一个名为 LLM-Verifier 的模型。验证器用生成的输入符号追踪目标方法,并检查执行是否确实遵循预期路径。如果验证失败,拒绝原因连同无效输入被反馈给 LLM-Path-Solver 以做迭代精炼。这个反馈驱动的过程持续到生成有效输入、或达到预定重试上限。一旦确认有效输入,生成的具体值作为路径引导示例被追加到下游测试生成提示中。
2.3 提示构造与测试用例生成
符号执行之后,候选路径及其对应输入参考被格式化成用于测试生成的提示。为丰富提供给 LLM 的上下文,我们通过直接在代码中把变量标注为注释来增强这些提示的显式类型信息。例如,一个像 Date date = new Date() 的初始化被转换为 Date date = new Date() // "date" 是一个 Date 类型的变量。我们类似地处理容器类型(如数组、ArrayList、Set 和 Map),追加元素类型标注,例如为 List<Integer> list = new List<>() 追加 // "list" 是一个 Integer 类型的 List。
图 1(提示构造部分)展示了整合路径解析信息的测试生成提示模板。路径信息组合三类代码:(1)变量定义或对象创建代码,带变量描述增强;(2)普通操作代码,如计算和方法调用;(3)条件或循环代码,用指示执行要求的 True/False 条件表示。最后,我们还在提示中追加一个来自 Z3 SMT 求解器或 LLM 的输入引导。
然后提示被喂给 LLM 以生成测试用例。如果生成的测试失败(例如由于编译或运行时错误),我们把错误信息连同失败的测试文件反馈给 LLM 以做迭代精炼。只有成功通过的测试被保留并追加到现有测试套件。增强的测试套件随后被重新评估覆盖率,过程重复直到达成目标覆盖率或达到预定上限。
3 实验
3.1 数据集
为确保公平比较并遵循最先进设置,我们使用与 Panta 相同的数据集,它包含来自 Defects4J 的 14 个真实主题。类数从 2 到 30,被测方法数从 31 到 586。表(原文表 3)呈现所选主题。Project 列表示项目名连同其 Defects4J 版本标识符。总共,我们评估 130 个类,含 2,971 个被测方法。在所有项目中,对象相关路径压倒性地主导执行,平均占全部路径的 80.96%,而纯数值路径仅占 19.04%。这一趋势在几乎所有主题中一致,表明真实 Java 程序主要由对象交互而非纯数值计算驱动。
数据集统计(14 个 Defects4J 项目):
| 标识 | 项目 | 类数 | 方法数 | 纯数值路径 | 对象相关路径 |
|---|---|---|---|---|---|
| Cli | Cli-40f | 2 | 31 | 6 (11.54%) | 46 (88.46%) |
| Codec | Codec-18f | 7 | 78 | 3 (1.62%) | 182 (98.38%) |
| Collections | Collections-28f | 5 | 218 | 15 (3.62%) | 399 (96.38%) |
| Compress | Compress-47f | 9 | 65 | 42 (13.68%) | 265 (86.32%) |
| Csv | Csv-16f | 3 | 72 | 21 (18.58%) | 92 (81.42%) |
| Gson | Gson-16f | 4 | 75 | 53 (17.15%) | 256 (82.85%) |
| JCore | JacksonCore-26f | 9 | 161 | 110 (23.26%) | 363 (76.74%) |
| JDatabind | JacksonDatabind-112f | 9 | 371 | 251 (25.18%) | 746 (74.82%) |
| JXml | JacksonXml-5f | 4 | 118 | 26 (5.83%) | 420 (94.17%) |
| Jsoup | Jsoup-93f | 8 | 171 | 74 (22.09%) | 261 (77.91%) |
| JXPath | JXPath-22f | 12 | 115 | 49 (7.95%) | 567 (92.05%) |
| Lang | Lang-4f | 17 | 586 | 273 (24.59%) | 837 (75.41%) |
| Math | Math-2f | 30 | 452 | 346 (22.97%) | 1,160 (77.03%) |
| Time | Time-13f | 11 | 458 | 141 (25.97%) | 402 (74.03%) |
| 总计/均值 | — | 130 | 2,971 | 1,410 (19.04%) | 5,996 (80.96%) |
为受控且可比的评估,我们丢弃每个项目的原始测试套件,并为所有目标类从零生成测试,这有助于消除现有测试引入的任何潜在偏差,并确保所有方法在相同条件下被评估。
3.2 基线与 LLM 选择
为评估 NeuroTestGen,我们把它与最先进的基于 LLM 的测试生成技术 Panta 比较——后者结合静态控制流分析和动态覆盖率反馈,以迭代引导 LLM 为未覆盖执行路径生成测试。
对实验 LLM 配置,我们遵循 Panta 并采用相同的评估协议、基准设置和语言模型,以确保公平一致的比较。具体来说,我们用与 Panta 相同的四个代表性大语言模型做实验,包括 Meta 的 Llama 3.3 70B、OpenAI 的 GPT-4o Mini 和 Anthropic 的 Claude 3.5 Haiku。此外,我们纳入一个强大的最先进、面向编码的模型 Claude Sonnet 4.6,以更好地为我们方法的性能提供上下文。
所有被评估的 LLM 都支持最多 128K token 的上下文窗口,确保处理大型代码上下文和规格的充足容量。为保持一致并消除混杂因素,我们在所有模型上固定解码参数:最大生成 token 数设为 4096,温度设为 0.2。这个相对较低的温度鼓励稳定、近乎确定性的输出,同时仍允许有限的变异性。
3.3 评估指标
我们采用测试生成文献中广泛使用的质量指标,包括行覆盖率、分支覆盖率、通过率和成本。
行覆盖率衡量生成测试套件演练的可执行源代码行的比例。它计算为至少执行一次的行数除以目标类中可执行行总数。分支覆盖率衡量测试套件执行的控制流分支(如 if、switch 和循环条件等条件语句的 true/false 结果)的比例。它计算为覆盖的分支数除以类中分支总数。通过率定义为纳入测试套件后成功执行的生成测试的百分比。一个测试若成功编译且运行无失败或运行时异常,则视为通过。成本:由于不同 LLM 产生不同的使用费用,我们报告 NeuroTestGen 配每个模型的相应金钱成本。
由于我们的评估在类级而非方法级进行,我们为每个类单独计算行和分支覆盖率,并报告每个项目内所有目标类的平均覆盖率。
4 结果
4.1 NeuroTestGen 性能的主要结果
Panta 报告其用 Claude-3.5-Haiku 取得最佳性能;因此,为确保与 Panta 的公平比较,我们采用 Claude-3.5-Haiku 作为主要评估模型之一,并使用其论文中报告的原始结果。此外,我们纳入最新的最先进、面向编码的模型 Claude Sonnet 4.6,以在更强 LLM 设置下进一步评估 NeuroTestGen 的有效性。
表 1:NeuroTestGen 与 Panta 跨项目的比较(两个基础模型:Claude 3.5 Haiku 和 Claude 4.6 Sonnet)
| 项目 | 行覆盖 Panta(3.5) | 行覆盖 NTG(3.5) | 行覆盖 Panta(4.6) | 行覆盖 NTG(4.6) | 分支 Panta(3.5) | 分支 NTG(3.5) | 分支 Panta(4.6) | 分支 NTG(4.6) |
|---|---|---|---|---|---|---|---|---|
| Cli | 91.14 | 91.14 | 98.82 | 98.82 | 82.74 | 83.15 | 92.08 | 92.49 |
| Codec | 83.30 | 83.91 | 98.45 | 98.45 | 79.40 | 80.70 | 94.86 | 95.03 |
| Collections | 80.35 | 82.14 | 98.97 | 99.24 | 80.59 | 81.79 | 96.36 | 96.79 |
| Compress | 59.69 | 62.80 | 91.91 | 92.76 | 51.28 | 57.57 | 85.04 | 86.79 |
| Csv | 58.11 | 74.90 | 83.80 | 86.19 | 46.42 | 62.44 | 73.56 | 77.14 |
| Gson | 85.19 | 88.01 | 92.05 | 92.05 | 74.25 | 80.06 | 88.52 | 88.52 |
| JCore | 73.88 | 76.32 | 87.70 | 89.06 | 67.01 | 69.84 | 85.94 | 87.42 |
| JDatabind | 35.00 | 51.22 | 86.95 | 88.34 | 34.45 | 47.69 | 82.17 | 83.86 |
| JXml | 46.42 | 54.57 | 77.20 | 77.20 | 50.34 | 58.47 | 79.70 | 79.70 |
| Jsoup | 86.75 | 88.36 | 96.05 | 96.90 | 73.38 | 79.08 | 88.41 | 90.12 |
| JXPath | 55.31 | 57.17 | 84.84 | 93.74 | 50.46 | 53.73 | 78.53 | 88.36 |
| Lang | 78.17 | 80.02 | 93.23 | 93.87 | 74.13 | 76.93 | 89.36 | 89.95 |
| Math | 80.77 | 84.98 | 95.87 | 96.37 | 73.60 | 78.71 | 92.42 | 93.37 |
| Time | 78.21 | 86.69 | 97.66 | 97.79 | 74.00 | 82.01 | 94.38 | 94.87 |
| 总计/均值 | 70.88 | 75.87 | 91.68 | 92.91 | 65.15 | 70.87 | 87.24 | 88.89 |
通过率(Panta → NeuroTestGen):Claude 3.5 从 65.92% 到 66.34%,Claude 4.6 从 96.81% 到 96.88%。
我们的主要结果呈现于表 1。总体而言,NeuroTestGen 在多数项目和指标上一致优于 Panta,在两种 LLM 设置下都达到更高的平均行覆盖率、分支覆盖率和通过率。这些结果证明了把符号执行与 LLM 引导的测试合成结合的有效性。对行覆盖率,NeuroTestGen 用 Claude 3.5 把平均覆盖率从 70.88% 改进到 75.87%,用 Claude 4.6 从 91.68% 改进到 92.91%,在 Csv、Jsoup 和 JXPath 等项目上有显著增益。对分支覆盖率,NeuroTestGen 用 Claude 3.5 把平均覆盖率从 65.15% 提升到 70.87%,用 Claude 4.6 从 87.24% 提升到 88.89%,展示了更强的覆盖困难执行路径的能力。NeuroTestGen 还保持了高测试有效性,用 Claude 3.5 把平均通过率从 65.92% 略微改进到 66.34%,用 Claude 4.6 从 96.81% 改进到 96.88%。
当使用像 Claude 3.5 这样的早期 LLM 时,NeuroTestGen 相比像 Claude 4.6 这样的更强模型取得了对 Panta 更大的改进。这表明 NeuroTestGen 引入的符号推理和约束求解能力能有效补偿较小或较不先进 LLM 较弱的推理能力。
4.2 不同模型的影响
表 2:NeuroTestGen 配不同 LLM 的性能(总计/均值)
| 指标 | Llama 3.3 | GPT-4o Mini | Claude 3.5 | Claude 4.6 |
|---|---|---|---|---|
| 行覆盖率 | 69.41 | 62.08 | 75.87 | 92.91 |
| 分支覆盖率 | 60.22 | 53.22 | 70.87 | 88.89 |
| 通过率 | 40.56 | 41.46 | 66.34 | 96.88 |
| 成本(美元) | 116.23 | 183.50 | 428.41 | 904.28 |
我们还检查了 NeuroTestGen 在不同 LLM 上的性能,以评估它在能力和成本各异的模型下的有效性和可泛化性。总体而言,性能在不同模型间差异显著,凸显了底层 LLM 对测试生成有效性的强烈影响。
在被评估模型中,Claude Sonnet 4.6 达到最高的平均行覆盖率(92.91%)、分支覆盖率(88.89%)和通过率(96.88%),展示了更强代码推理和生成能力的益处。Claude 3.5 Haiku 也表现有竞争力,达到 75.87% 行覆盖率和 70.87% 分支覆盖率,表明 NeuroTestGen 能有效利用中型 LLM 达成强大测试性能。相比之下,Llama 3.3 和 GPT-4o Mini 表现出明显更低的性能,尤其在通过率和分支覆盖率上,表明即使有符号引导,较弱的 LLM 在生成有效测试和满足复杂执行约束方面更挣扎。尽管如此,NeuroTestGen 仍使这些较小模型能在多个项目上达成合理覆盖率,凸显了混合符号执行与 LLM 引导框架的稳健性。
图 4 比较了不同 LLM 的生成成本。Llama 3.3 70B 产生最低成本(116.23 美元),其次是 GPT-4o-Mini(183.50 美元)和 Claude 3.5 Haiku(428.41 美元),而 Claude Sonnet 4.6 最昂贵,为 904.28 美元。虽然 Claude Sonnet 4.6 达到最佳覆盖率和通过率,这些增益以显著成本为代价,需要约 7.8 倍于 Llama 3.3 70B、4.9 倍于 GPT-4o-Mini 的成本。相比之下,Claude 3.5 Haiku 在性能和成本之间提供更优惠的平衡,以显著更低的开销达成有竞争力的测试生成质量。
4.3 消融研究
如第 2 节所讨论,执行路径包括纯数值和对象相关路径。虽然纯数值路径能被符号执行有效处理,对象相关路径更具挑战、需要基于 LLM 的支持。本节中,我们把仅用符号执行的 NeuroTestGen 与完整 NeuroTestGen 框架比较,以评估 LLM 组件在路径求解中的贡献。
表 3:消融研究(仅符号 vs 完整 NeuroTestGen)总计/均值
| 指标 | 仅符号(3.5) | 完整(3.5) | 仅符号(4.6) | 完整(4.6) |
|---|---|---|---|---|
| 行覆盖率 | 73.45 | 75.87 | 92.35 | 92.91 |
| 分支覆盖率 | 68.53 | 70.87 | 88.15 | 88.89 |
总体而言,整合 LLM 引导的测试合成相比仅符号执行一致改进了行和分支覆盖率。用 Claude 3.5,完整框架把平均行覆盖率从 73.45% 改进到 75.87%,分支覆盖率从 68.53% 改进到 70.87%。类似地,在 Claude Sonnet 4.6 下,完整框架把平均行覆盖率从 92.35% 提升到 92.91%,分支覆盖率从 88.15% 提升到 88.89%。完整 NeuroTestGen 框架相比仅符号变体的改进相对较小,部分由于现代 LLM 强大的固有能力。即使不显式求解对象相关约束,LLM 也常能从学到的编程模式推断合理的对象构造、API 序列和输入值,使仅符号变体能达成相对强的性能。
尽管如此,完整 NeuroTestGen 框架一致表现更好,尤其在面向对象逻辑和 API 交互复杂的项目上。这些结果凸显了符号执行与基于 LLM 的合成的互补优势:符号执行提供精确的路径推理,而 LLM 贡献语义理解和灵活的测试生成。
5 相关工作
5.1 基于 LLM 的测试生成
用 LLM 做自动化单元测试生成近年已被广泛研究。AthenaTest 用在焦点方法上下文上训练的 transformer 模型生成单元测试,ATLAS 提出预测有意义断言以强化缺陷检测的神经方法。随后,TOGA 表明机器学习模型能从现有测试和文档学习断言模式并成功生成有用的 oracle。CodaMosa 调用模型以在基于搜索的生成中逃脱覆盖率平台期,而 Cedar 检索有效示例以稳定断言相关任务的 few-shot 提示。Shin 等人进一步研究检索增强的测试生成,表明为 LLM 提供外部领域知识能改进库 API 的单元测试生成。ChatUniTest 引入迭代验证和修复机制以修复失败测试,MuTAP 纳入来自变异测试的反馈以改进测试用例有效性。更近期,Steenhoek 等人提出一个用来自自动质量指标的强化学习的方法,帮助减少测试坏味道。Panta 用一个混合方法,通过用静态程序分析揭示未覆盖路径来给 LLM 更多信息,从而提升行和分支覆盖率;ASTER 引入一个通用的、多语言的单元测试生成流水线,结合程序分析与环境 mock 以处理真实软件系统。总之,这些研究显示了从一次性提示转向迭代式、反馈引导的测试生成的转变,后者同时改进覆盖率和测试有效性。
5.2 符号执行
符号执行是一种白盒程序分析技术,它用符号值代替具体输入运行程序,并累积一个捕捉遵循每条被探索执行路径所需约束的路径条件。通过求解这些约束,它能获得引导程序执行走向特定分支和行为的具体输入,使其有助于系统性测试用例生成。早期工作确立了符号执行用于程序测试的核心思想,而混合符号执行(如 CUTE)把具体运行与符号推理结合,以迭代取反分支谓词并生成路径多样性更高的新测试。像 KLEE 这样可扩展的引擎进一步证明符号执行能为复杂系统自动生成高覆盖率测试,但也凸显了挑战,包括路径爆炸和约束求解器瓶颈。
近期研究通过把 LLM 与符号和混合符号执行整合来重访这些挑战以改进测试生成。PALM 有意避免基于 SMT 的约束求解,方法为把路径翻译成 LLM 可解读的可执行变体。Wang 等人提出 LLM-Sym 把复杂 Python 路径约束翻译成 Z3 代码。SymPrompt 研究覆盖率引导的回归测试生成,提出一个多阶段提示策略,使生成与执行路径对齐,同时喂入类型和依赖上下文,从而帮助模型产出可执行测试并在实践中逃脱覆盖率平台期。Cottontail 把 LLM 驱动的求解纳入混合符号执行,为程序生成高度结构化的输入以避免浪费测试努力。
与先前研究不同,我们的方法在一个统一的路径求解框架中把精确符号推理与基于 LLM 的语义理解结合。通过自适应地对数值约束路径应用基于 SMT 的符号执行、对语义复杂路径应用验证器引导的 LLM 推理,我们的方法改进了在真实测试生成场景中求解未覆盖执行路径的准确率和有效性。
6 结论
本文提出 NeuroTestGen,一个把符号执行与 LLM 驱动的测试合成结合来生成测试用例的混合方法。我们在标准基准上的评估表明 NeuroTestGen 显著优于最先进方法。尽管有这些有前景的结果,NeuroTestGen 仍有若干局限。第一,符号执行的有效性仍受可扩展性挑战约束,如路径爆炸和对复杂堆状态的不完整建模。第二,虽然 LLM 引导改进了对象构造和 API 使用生成,该方法在高度领域特定的库或需要深度语义理解的程序上仍可能挣扎。最后,迭代精炼过程因反复的编译、执行和提示循环引入额外计算开销。这些局限凸显了未来工作的机会:改进符号可扩展性、增强语义推理能力,以及降低生成成本。
数据可用性声明:作者在 https://anonymous.4open.science/r/Symbolic_Execution_Based_Test_Generation-F4F3/ 提供数据集和源代码。
署名与许可:原文 NeuroTestGen: Neuro-Symbolic Guided Test Generation with Large Language Models,作者 Ruixin Zhang、Jiho Shin、Hung Viet Pham、Song Wang(York University),arXiv:2609.30178v1 [cs.SE],2026-09-24。原文以 CC BY 4.0 许可发布。中文全译由智测团队完成,译文同样以 CC BY 4.0 发布;图 1、图 3 版权归原作者。原文地址:https://arxiv.org/abs/2609.30178 。代码与数据:https://anonymous.4open.science/r/Symbolic_Execution_Based_Test_Generation-F4F3/ 。译文中省略了参考文献列表、文内引注编号,以及未随 HTML 提供的附录 A(失败分析)、附录 B(影响声明);模型名、工具名、基准名、指标名保留英文。表 1–3 为节省篇幅对原文多列大表做了重组,数值与原表一致,完整排版请以英文原文为准。如译文与原文有出入,以英文原文为准。
Found it useful? Pass it on
Scan with WeChat to open it on your phone and forward it.