fuzz函数必须是func fuzzxxx(f testing.f),因go模糊测试引擎仅通过该签名识别入口点;若命名非大驼峰、参数非testing.f或文件非_test.go,将静默跳过。

Fuzz 函数不是“多写几个测试用例”的替代品,而是专门用来暴露你根本没想过会出问题的输入。它不关心逻辑是否正确,只负责把边界、畸形、超长、编码异常的输入塞进去,看程序会不会 panic、死锁、内存越界或返回垃圾结果。
为什么 Fuzz 函数签名必须是 func FuzzXxx(f *testing.F)
Go 的模糊测试引擎靠函数签名识别入口点。如果写成 func FuzzXxx(t *testing.T) 或 func fuzzXxx(f *testing.F)(小写开头),go test -fuzz=. 就完全找不到它。Fuzz 必须大写开头,参数类型严格为 *testing.F,且不能有返回值——这是引擎解析和调度的硬性契约。
f.Fuzz 里传入的参数类型受限,不是所有类型都能 fuzz
你不能在 f.Fuzz 回调里声明 func(t *testing.T, req *http.Request) 或 func(t *testing.T, cfg Config)。只支持基础类型:string、[]byte、整数族(int/int64/uint8 等)、浮点数、bool。Rune 被视为 int32,所以能用;但 struct、指针、channel、func 类型统统被拒绝,编译期就会报错。
- 想 fuzz 结构化数据(比如 JSON body)?先用
string或[]byte接收,再在回调里json.Unmarshal - 想控制字段组合?靠种子语料库(
f.Add("{'name':'a','age':-1}"))引导变异方向,而不是在类型上绕开限制 - 别试图用
unsafe.Pointer强转——这不会让 fuzzer 生成合法输入,只会让测试直接失败
崩溃复现难,往往是因为忽略了 testdata/fuzz/ 下的语料文件
一旦 Fuzz 发现 panic,Go 会自动生成一个以函数名命名的子目录(如 testdata/fuzz/FuzzProcessPrompt/),里面存着触发崩溃的最小输入(000001.fuzz)。这个文件不是日志,而是可复现的“证据”。
- 下次运行
go test -fuzz=FuzzProcessPrompt,fuzzer 会自动加载它,并优先变异该输入——这是回归验证的关键 - 如果你删了整个
testdata/fuzz/目录,就等于丢掉了所有已发现的崩溃现场,再跑一遍可能要等几十分钟才能重新触发 - CI 中建议把
testdata/fuzz/提交进 Git——它体积小、结构稳定,且是 fuzz 测试闭环的必要部分
\u200d 时返回空字符串” 这类逻辑错误,除非你在 f.Fuzz 回调里显式 t.Error,否则它永远沉默。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











