虽然已经有许多模糊测试工具存在很长时间了(例如 oss-fuzz
),但自 Go 1.18 开始,模糊测试被添加到了Go的标准库中。现在它作为常规测试包的一部分,因为它是测试的一种。你还可以将它与其他测试原语一起使用,这很方便。
在Go中创建模糊测试的步骤如下:
- 在
_test.go
文件中,创建一个以Fuzz
开头并接受*testing.F
的函数 - 使用
f.Add()
添加语料库种子,让模糊测试器基于它生成数据 - 使用
f.Fuzz()
调用模糊测试目标,传递我们的目标函数接受的模糊测试参数 - 使用常规的
go test
命令启动模糊测试器,但要加上--fuzz=Fuzz
标志
注意,模糊测试参数只能是以下类型:
- string, byte, []byte
- int, int8, int16, int32/rune, int64
- uint, uint8, uint16, uint32, uint64
- float32, float64
- bool
上面Equal函数的简单模糊测试可能如下所示:
// 模糊测试
func FuzzEqual(f *testing.F) {
// 添加种子语料库
f.Add([]byte{'f', 'u', 'z', 'z'}, []byte{'t', 'e', 's', 't'})
// 带有模糊测试参数的模糊测试目标
f.Fuzz(func(t *testing.T, a []byte, b []byte) {
// 调用我们的目标函数并传递模糊测试参数
Equal(a, b)
})
}
默认情况下,模糊测试会永远运行,所以你要么需要指定时间限制,要么等待模糊测试失败。你可以使用 --fuzz
参数指定要运行的测试。
go test --fuzz=Fuzz -fuzztime=10s
如果执行过程中出现任何错误,输出应该类似于这样:
go test --fuzz=Fuzz -fuzztime=30s
--- FAIL: FuzzEqual (0.02s)
--- FAIL: FuzzEqual (0.00s)
testing.go:1591: panic: runtime error: index out of range
Failing input written to testdata/fuzz/FuzzEqual/84ed65595ad05a58
To re-run:
go test -run=FuzzEqual/84ed65595ad05a58
注意,导致模糊测试失败的输入被写入 testdata
文件夹中的文件,可以使用该输入标识符重新运行:
go test -run=FuzzEqual/84ed65595ad05a58
testdata
文件夹可以提交到代码库中,并用于常规测试,因为模糊测试在没有 --fuzz
标志的情况下也可以作为常规测试运行。