Go 模糊测试实战:用 testing.F 与 fuzz target 找出隐藏的边界崩溃
test12026-10-210 次阅读
什么是 fuzz 测试
单元测试靠你手写的样例,覆盖的是你“想到”的输入。模糊测试让 Go 在种子输入的基础上,自动变异出海量随机输入,持续轰击你的函数,专门抓那些没想到的边界:空串、超长串、特殊字符、负数。Go 1.18 起标准库自带 testing.F,无需第三方框架。
写一个 fuzz target
函数名以 Fuzz 开头,参数是 *testing.F。先 f.Add 放几个种子,再用 f.Fuzz 定义对每一个输入都成立的不变式。
package parse
import (
"strings"
"testing"
)
func Normalize(input string) string {
return strings.TrimSpace(strings.ToLower(input))
}
func FuzzNormalize(f *testing.F) {
f.Add(" Hello ")
f.Add("WORLD")
f.Fuzz(func(t *testing.T, input string) {
out := Normalize(input)
if out != strings.TrimSpace(strings.ToLower(input)) {
t.Fatalf("unexpected: %q", out)
}
})
}真实案例:解析一行 CSV
解析函数很容易在空字段、前后空格、只有单个逗号这些输入上翻车。下面给一个宽松版本加不变式,至少保证“一定返回一个字段”。
func ParseCSVLine(line string) []string {
fields := strings.Split(line, ",")
for i := range fields {
fields[i] = strings.Trim(fields[i], " ")
}
return fields
}
func FuzzParseCSVLine(f *testing.F) {
f.Add("a,b,c")
f.Add("")
f.Fuzz(func(t *testing.T, line string) {
fields := ParseCSVLine(line)
if len(fields) == 0 {
t.Fatal("expected at least one field")
}
})
}运行与语料库
执行 go test -fuzz=FuzzParseCSVLine -fuzztime 30s。一旦崩溃,Go 会把触发崩溃的最小输入写进 testdata/fuzz,并自动生成一条普通单元测试,下次直接回归。之后可以把那条失败输入手动复查、修代码、再跑,形成闭环。
- 模糊测试跑得久才有价值,建议放进 CI 给足时间预算。
- 不变式要写得稳:宁可少断言,也别写出本身不成立的断言导致误报。
- 崩溃输入会被固化成用例,相当于让 fuzz 帮你写了回归测试。
T
test1
文章作者
什么是 fuzz 测试 单元测试靠你手写的样例,覆盖的是你“想到”的输入。模糊测试让 Go 在种子输入的基础上,自动变异...
- 分类
- 技术
- 发布时间
- 2026-10-21
- 字数
- 约 1280 字
- 阅读
- 0 次
