在golang 1.18中,新增了模糊测试特性fuzzing。 模糊测试(fuzz testing, fuzzing)是一种软件测试技术, 模糊测试是一种自动测试,它不断地操纵程序的输入来发现错误。Go fuzzing使用覆盖率指导来智能地遍历被模糊处理的代码,以发现bug并向用户报告BUG。由于模糊测试可以触及人类经常错过的边缘情况,因此它对于发现安全漏洞和漏洞尤其有价值。 下面是一个模糊测试的例子,突出显示了它的主要组件。
1、创建一个main.go 内容为
package mainimport ( "fmt")func main() { input := "The quick brown fox jumped over the lazy dog" rev := Reverse(input) doubleRev := Reverse(rev) fmt.Printf("original: %q\n", input) fmt.Printf("reversed: %q\n", rev) fmt.Printf("reversed again: %q\n", doubleRev)}func Reverse(s string) string { b := []byte(s) for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 { b[i], b[j] = b[j], b[i] } return string(b)}
2、写一个单元测试reverse_test.go
package mainimport ( "testing")func TestReverse(t *testing.T) { testcases := []struct { in, want string }{ {"Hello, world", "dlrow ,olleH"}, {" ", " "}, {"!12345", "54321!"}, } for _, tc := range testcases { rev := Reverse(tc.in) if rev != tc.want { t.Errorf("Reverse: %q, want %q", rev, tc.want) } }}
运行单元测试
$ go test -v=== RUN TestReverse--- PASS: TestReverse (0.00s)PASSok demo 0.030s
接下来,您将把单元测试更改为模糊测试。
3、添加模糊测试
单元测试有局限性,即每个输入都必须由开发人员添加到测试中。模糊化的一个好处就是,它为代码提供了输入,并可能识别出您提出的测试用例没有达到的边缘用例。 在本节中,将把单元测试转换为模糊测试,这样就可以用更少的工作生成更多的输入! 请注意,您可以将单元测试、基准测试和模糊测试保存在同一个*_test.go文件中,但在本例中,您将把单元测试转换为模糊测试。
将reverse_test.go中的单元测试替换为以下模糊测试。
func FuzzReverse(f *testing.F) { testcases := []string{"Hello, world", " ", "!12345"} for _, tc := range testcases { f.Add(tc) // Use f.Add to provide a seed corpus } f.Fuzz(func(t *testing.T, orig string) { rev := Reverse(orig) doubleRev := Reverse(rev) if orig != doubleRev { t.Errorf("Before: %q, after: %q", orig, doubleRev) } if utf8.ValidString(orig) && !utf8.ValidString(rev) { t.Errorf("Reverse produced invalid UTF-8 string %q", rev) } })}
执行模糊测试
$ go test -v -fuzz=Fuzz -fuzztime 10s === RUN FuzzReversefuzz: elapsed: 0s, gathering baseline coverage: 0/13 completedfailure while testing seed corpus entry: FuzzReverse/31d6dcd7535b857afuzz: elapsed: 0s, gathering baseline coverage: 3/13 completed--- FAIL: FuzzReverse (0.12s) --- FAIL: FuzzReverse (0.00s) reverse_test.go:20: Reverse produced invalid UTF-8 string "\xb3\xb3\xef"=== NAMEFAILexit status 1FAIL demo 0.149s
另一个有用的选项是-fuzztime,它限制了模糊处理所花费的时间。例如,在下面的测试中指定-fuzztime 10s意味着,只要之前没有发生故障,测试将在10秒后默认退出。-fuzz 选项,指执行正则表达式匹配到的测试函数。请参阅cmd/go文档的这一部分,以查看其他测试选项。
https://go.dev/doc/security/fuzz/
https://go.dev/doc/tutorial/fuzz
https://blog.jetbrains.com/go/2022/12/14/understanding-fuzz-testing-in-go/