Go模糊测试实战:让AI帮你找Bug
大家好,我是极客老墨。 之前写过一篇Go 测试:写得爽,跑得快,聊了单元测试、表格驱动测试和基准测试。很多朋友留言问:“老墨,单元测试我会写了,但总感觉测不全,怎么办?” 这就是今天要聊的:模糊测试(Fuzzing)。 写代码爽,写测试累。更累的是,你辛辛苦苦写了一堆单元测试,覆盖率看起来挺高,结果上线还是出Bug。为啥?因为你只测了你能想到的场景,没测你想不到的。 Go 1.18 开始,官方直接把模糊测试内置了。它会自动生成海量随机输入,帮你找到那些"想不到的 Bug"。不需要装第三方库,go test 就能跑。 什么是模糊测试?一句话说清楚 模糊测试就是让程序自己生成各种奇葩输入,疯狂测试你的代码,直到找出Bug为止。 传统单元测试:你说测什么就测什么。 模糊测试:程序自己想办法搞你,直到搞出问题。 从Go 1.18开始,Go官方在标准库里内置了Fuzzing支持。不需要装第三方工具,开箱即用。 为什么要用模糊测试? 老墨先给你看个真实案例。 假设你写了个URL解析函数,单元测试写了10个case,都通过了。结果上线后,用户输入了一个带emoji的URL,程序直接panic。 为什么?因为你的测试用例里没有emoji。 单元测试的局限性: 只能测你想到的场景 边缘情况容易遗漏 维护成本高(每个case都要手写) 模糊测试的优势: 自动生成海量测试数据 能发现你想不到的边缘情况 特别擅长找安全漏洞(SQL注入、缓冲区溢出等) 实战案例:一个看似简单的字符串反转函数 我们来写个最简单的函数:反转字符串。 1func Reverse(s string) string { 2 b := []byte(s) 3 for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 { 4 b[i], b[j] = b[j], b[i] 5 } 6 return string(b) 7} 看起来没问题吧?我们写个单元测试: 1func TestReverse(t *testing.T) { 2 testcases := []struct { 3 in, want string 4 }{ 5 {"Hello, world", "dlrow ,olleH"}, 6 {" ", " "}, 7 {"!12345", "54321!"}, 8 } 9 for _, tc := range testcases { 10 rev := Reverse(tc.in) 11 if rev != tc.want { 12 t.Errorf("Reverse: %q, want %q", rev, tc.want) 13 } 14 } 15} 运行测试: ...