介绍
在 Go 1.18 之前,Go 语言支持功能测试、基准测试和示例测试,在 Go 项目开发中,使用最多的是功能测试,读者朋友们应该都比较熟悉功能测试的使用方式了。
在 Go 1.18 中,Go 语言新增模糊测试,本文我们介绍模糊测试的使用方式。
使用方式
Go 语言的模糊测试,与其他三种测试方式相同,测试文件的文件名以 _test.go
结尾,测试文件中必须导入 testing
包。
模糊测试与其他三种测试方式的不同点是,函数名和函数签名不同。
我们在之前关于 Go 测试的文章中介绍过,功能测试的函数名以 Test
开头,函数签名是 t testing.T
。
性能测试的函数名以 Benchmark
开头,函数签名是 b testing.B
。
模糊测试的函数名以 Fuzz
开头,函数签名是 f testing.F
。
与功能测试和性能测试相同,运行模糊测试也是使用 go test
命令,读者朋友们可以运行 go help test
或 go help testflag
了解更多。
03
模糊测试示例
Go 语言功能测试需要我们预定义测试值和与之对应的期望得到的值,如果测试输出结果值与预先定义的期望值相同,则认为通过测试,反之,则认为未通过测试。
示例代码:
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) }
功能测试代码:
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) } } }
阅读上面这段代码,我们定义一个反转字符串的函数 Reverse
,并定义一个功能测试函数 TestReverse
,读者朋友们应该非常熟悉类似的功能测试代码。
但是,在实际项目开发中,我们很难考虑到所有测试用例,比如上面这段代码运行结果是通过测试,我们一般就会认为定义的反转字符串函数 Reverse
功能正常。
实际结果并非如此,我们在测试用例中加入一组中文字符串,{"我爱学编程", "程编学爱我"},
,我们再运行功能测试代码,得到的结果就是未通过。
聪明的读者朋友们,应该已经发现问题在哪,修复该问题也很简单,只需将 []byte
改为 []rune
,当然,这不是本文的重点,我们也就不深入解释问题的原因了。
模糊测试,就是 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) } }) }
阅读上面这段代码,我们将功能测试代码转换为模糊测试代码,仔细分析这段代码,我们可以发现,我们将功能测试中的输入测试用例,通过 f.Add
将其作为模糊测是的种子语料库。
在功能测试代码的函数签名中,新增一个字符串类型的参数 orig
,将 orig
原值经过两次反转,如果最终结果与 orig
不同,则为未通过测试,并将该代码作为 f.Fuzz
的参数,这里的 orig
称为模糊参数。
需要注意的是,运行模糊测试函数时,首次先不要使用 -fuzz
,以确保种子输入可以通过。
然后,在运行 go test -fuzz=Fuzz
(也可以使用完整模糊测试函数名),运行失败时,将导致运行失败的输入写入种子语料库。
接着,就是调式代码,直到通过模糊测试,限于篇幅,我们不讲述调试过程。
需要注意的时,当模糊测试可以通过时,模糊测试将一直运行,我们需要使用 ctrl-C
结束程序。或者使用 -fuzztime 30s
,代表如果模糊测试通过,运行 30s 将自动停止。
04
总结
本文我们介绍 Go 模糊测试的使用方式,它可以很好地解决功能测试无法考虑到所有边界问题的情况。
关于模糊测是的更多内容,感兴趣的读者朋友们可以阅读官方教程。
推荐阅读:
参考资料: