拓展阅读
开源 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息)
开源 Junit performance rely on junit5 and jdk8+.(java 性能测试框架。性能测试。压测。测试报告生成。)
test fuzz-01-模糊测试(Fuzz Testing)
test fuzz-02-模糊测试 JQF + Zest Semantic Fuzzing for Java
test fuzz-03-模糊测试 Atheris A Coverage-Guided, Native Python Fuzzer
test fuzz-04-模糊测试 jazzer Coverage-guided, in-process fuzzing for the JVM
test fuzz-05-模糊测试 kelinci AFL-based fuzzing for Java
test fuzz-06-模糊测试 AFL american fuzzy lop - a security-oriented fuzzer
test fuzz-07-模糊测试 libfuzzer
JQF
JQF是Java的一种反馈导向的模糊测试平台(类似于AFL/LibFuzzer,但针对JVM字节码)。
JQF使用基于属性的测试的抽象,使得编写模糊驱动程序作为参数化JUnit测试方法变得很容易。
JQF建立在junit-quickcheck之上。
JQF通过使用Zest等基于覆盖引导的模糊算法,使运行junit-quickcheck风格的参数化单元测试具有强大的能力。
[Zest][ISSTA’19 paper]是一种算法,通过偏向于生成语义有效的输入来引导覆盖引导的模糊测试;即,在最大化代码覆盖的同时满足结构和语义属性的输入。
Zest的目标是发现传统模糊测试工具无法发现的深层语义错误,这些工具主要只强调错误处理逻辑。
默认情况下,JQF通过简单的命令运行Zest:mvn jqf:fuzz
。
JQF是一个模块化的框架,支持以下可插拔的模糊测试前端,称为引导:
- 使用AFL进行二进制模糊测试 (教程)
- 使用**Zest**进行语义模糊测试 [[ISSTA’19 paper]] (教程 1) (教程 2)
- 使用**PerfFuzz**进行复杂性模糊测试 [[ISSTA’18 paper]]
- 使用**RLCheck**进行强化学习(基于JQF的一个分支) [[ICSE’20 paper]]
- 使用**Mu2**进行突变分析引导的模糊测试 [[ISSTA’23 paper]]
概述
什么是结构感知模糊测试?
像AFL和libFuzzer这样的二进制模糊测试工具将输入视为字节序列。如果测试程序期望高度结构化的输入,例如XML文档或JavaScript程序,则对字节数组进行变异通常会导致语法无效的输入;测试程序的核心部分保持未经测试。
结构感知模糊测试工具利用对输入格式的领域特定知识,通过构造产生语法有效的输入。有一些关于使用libFuzzer进行C++和Rust程序结构感知模糊测试的很好的文章。
什么是基于生成器的模糊测试(QuickCheck)?
结构感知模糊测试工具需要一种理解输入结构的方法。其他一些工具使用输入格式的声明性规范,例如上下文无关文法或协议缓冲区。JQF使用QuickCheck的命令式方法来指定输入空间:任意的生成器程序,其任务是生成单个随机输入。
Generator<T>
提供了生成类型为T
的随机实例的方法。例如,对于类型为Calendar
的生成器,它返回随机生成的Calendar
对象。可以轻松编写更复杂类型的生成器,比如
XML文档,
JavaScript程序,
JVM类文件,SQL查询,HTTP请求等等等 - 这就是基于生成器的模糊测试。然而,仅仅对类型为T
的随机输入进行采样通常不是很有效,因为生成器不知道它产生的输入是否有效。
什么是语义模糊测试(Zest)?
JQF支持**[Zest算法][ISSTA’19 paper],该算法使用代码覆盖和输入有效性反馈来偏向于生成结构化输入,从而揭示深层次的语义错误。
JQF使用字节码插装提取代码覆盖,使用JUnit的Assume
API提取输入有效性。
如果没有违反假设,输入就是有效的。
示例
以下是用于检查Apache Commons Collections中PatriciaTrie类属性的JUnit-Quickcheck测试。该属性测试如果PatriciaTrie
使用输入的JDK Map
初始化,并且如果输入映射已经包含一个键,则新构建的PatriciaTrie
中也应存在该键。
@RunWith(JQF.class)
public class PatriciaTrieTest {
@Fuzz /* 此方法的参数将由JQF自动生成 */
public void testMap2Trie(Map<String, Integer> map, String key) {
// 键应存在于映射中
assumeTrue(map.containsKey(key)); // 如果这个谓词不为真,测试无效
// 使用输入`map`创建新的trie
Trie trie = new PatriciaTrie(map);
// 该键也应存在于trie中
assertTrue(trie.containsKey(key)); // 当map = {"x": 1, "x\0": 2}和key = "x"时失败
}
}
运行mvn jqf:fuzz
将导致JQF重复调用testMap2Trie()
方法,并自动生成map
和key
的值。大约在平均5秒后(~5,000个输入),JQF将报告断言违规。它发现了在PatriciaTrie
的实现中的一个bug,截至v4.4尚未解决。对map
和key
值的随机抽样不太可能找到失败的测试用例,这是一个非常特殊的极端情况(请参阅上述代码中断言旁边的注释)。JQF使用名为[Zest][ISSTA’19 paper]的覆盖引导调用很容易找到此违规。要将此示例作为独立的Maven项目运行,请查看jqf-zest-example存储库。
在上面的示例中,Map
和String
的生成器是由JUnitQuickCheck自动生成的。也可以手动为结构化输入指定生成器。