LISP:基于大语言模型的库API输入空间划分测试技术

本文完整解析ICSE’25论文提出的创新测试工具LISP,通过大语言模型实现智能化的API测试

什么是LISP?

LISP(LLM based Input Space Partitioning)是一项突破性的软件测试技术。它能利用大语言模型(LLM)深入理解库API的代码逻辑,并基于这种理解自动完成输入空间的智能划分。简单来说,它让AI像专业测试工程师一样分析代码,自动生成高质量的测试用例。

技术亮点

  • 🧠 代码理解能力:LLM直接分析API源代码
  • 📊 智能分区策略:基于代码语义划分输入空间
  • 💡 常识知识融合:结合通用领域知识优化测试
  • 🏆 学术认可:入选软件工程顶会ICSE 2025

ACM认证标志
项目已通过ACM科研复现认证


环境配置指南(手把手安装)

系统要求

组件 要求
操作系统 Ubuntu 20.04/22.04 (x86架构)
内存 ≥4 GB RAM
Java JDK 11+
Python 3.10+
构建工具 Maven 3.6+

安装四步曲

  1. 安装Java依赖
    进入llm-JQF目录执行:

    mvn install -DskipTests
    
  2. 配置API密钥
    llm-JQF目录运行:

    sh set-key.sh -k <Your_API_Key> -b https://api.openai.com/v1
    

    💰 成本提示:完整运行约需$40的OpenAI token费用

  3. 安装Python依赖
    进入llm-seed-generator目录执行:

    pip3 install -r requirements.txt
    
  4. 准备测试API
    预置2205个API方法签名位于:

    LISP/llm-JQF/signs/
    ├── commons-lang3
    ├── guava
    └── ...
    

实战操作手册

核心工具

主执行文件位于:./llm-JQF/bin/jqf-llm
关键参数说明:

-i  # 启用覆盖率统计
-o  # 输出覆盖率结果
-l  # 指定签名文件(批量测试)
-s  # 实验模式选择:
    #   cg → LISP-CG模式
    #   skipUnder → 消融实验1
    #   skipEP → 消融实验2
    #   basic → LLM基线测试

单API测试示范

测试Guava库的Longs.min方法:

bin/jqf-llm -i -o "com.google.guava:guava:32.1-jre" \
"com.google.common.primitives.Longs.min(long[])"

成功输出示例

Semantic Fuzzing with LLM
--------------------------
Test signature: org.apache.commons.lang3.ArrayUtils.addAll(boolean[],boolean[])
Elapsed time: 3s
Number of executions: 4
Valid inputs: 4 (100.00%)
Unique failures: 0
API Coverage: 11 branches (100.00% of 11)
Total Coverage: 16 branches (100.00% of 16)

批量测试流程

注意:文件中所有API必须属于同一库

bin/jqf-llm -i -o -l signs/guava -s cg \
"com.google.guava:guava:32.1.2-jre"

结果深度解析

结果目录结构

result/
├── commons-lang3_cg_1737620727667.json  # 概要报告
└── details/
    ├── commons-lang3/
    │   ├── cg/
    │   │   ├── ArrayUtils.addAll(...)0/
    │   │   │   ├── coverage_hash    # 覆盖路径哈希
    │   │   │   ├── detail.json      # 详细数据
    │   │   │   ├── graph.json       # 方法调用图
    │   │   │   ├── input_generator  # LLM生成的输入
    │   │   │   ├── llm_output.log   # LLM交互日志
    │   │   │   └── RunCode.java     # 测试用例代码

关键数据文件说明

1. 概要报告(JSON格式)

{
  "coverage":1.0,             // 覆盖率
  "coveredEdge":11,           // 覆盖分支数
  "generatedInputsNum":6,     // 生成输入总数
  "inputToken":9449,          // 输入token消耗
  "outputToken":969,          // 输出token消耗
  "runTime":27950,            // 运行时间(ms)
  "successAPINum":1,          // 成功测试API数
  "totalEdge":11,             // 总分支数
  "unexpectedBehaviorNum":0   // 异常行为数
}

2. 详细数据(detail.json)

包含方法级别的:

  • 分支覆盖详情
  • 执行路径记录
  • 异常行为日志
  • token消耗明细

实验评估方法论

RQ1:代码覆盖能力

  • 评估指标:分支覆盖率
  • 数据源

    • 概要报告的coverage字段
    • detail.json中的分支覆盖详情
  • 分析重点:LISP与传统方法的覆盖率对比

RQ2:错误检测能力

  • 评估指标:异常行为数量
  • 数据源

    • 概要报告的unexpectedBehaviorNum
    • detail.json中的异常堆栈信息
  • 分析重点:检测到的边界条件错误

RQ3:执行成本分析

  • 核心指标

    • Token消耗(inputToken/outputToken)
    • 执行时间(runTime)
  • 优化方向:降低LLM交互成本

RQ4:消融实验设计

模式参数 测试内容
-s cg 完整LISP-CG
-s skipUnder 消融实验1 (ISP+OI)
-s skipEP 消融实验2 (TDA+OI)
-s basic LLM基线方法

技术问答(FAQ)

Q1:为什么需要4GB内存?

A:LLM推理和代码分析需要较大内存空间,实测低于4GB会导致OOM错误

Q2:如何查看具体的测试输入?

A:在details/<库名>/<模式>/<方法名>/input_generator文件中查看LLM生成的原始输入

Q3:token成本如何预估?

A:参考公式:
总成本 ≈ (inputToken/1000)×$0.01 + (outputToken/1000)×$0.03

Q4:能测试私有方法吗?

A:目前仅支持public API,私有方法需通过公有接口间接测试

Q5:结果中的coverage_hash有什么用?

A:用于快速比对不同运行的覆盖路径差异,避免重复计算


结语:测试技术的智能化演进

LISP代表了API测试领域的范式转变:

  1. 人机协作:结合LLM的代码理解与人类测试经验
  2. 动态分区:基于代码语义的智能输入空间划分
  3. 知识融合:将通用领域知识注入测试过程
  4. 量化评估:通过四维度研究问题系统验证效果