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} 运行测试: ...

2026-02-26 · 5 min · 936 words · 老墨

(译)进入Go模糊测试的世界

原文地址: https://go.dev/doc/tutorial/fuzz[] 本教程介绍了 Go 中模糊测试的基础知识。模糊测试会针对您的测试准备一些随机数据然后运行测试时使用它们,以尝试找出漏洞或导致崩溃的输入。可以通过模糊测试发现的一些漏洞示例包括 SQL 注入、缓冲区溢出、拒绝服务和跨站点脚本攻击(XSS)。 在本教程中,您将为一个简单的函数编写一个模糊测试,运行 go 命令,并调试和修复代码中的问题。 有关本教程中术语的帮助,请参阅 “词汇表”。 您将逐步完成以下部分: «为您的代码创建一个文件夹» «添加代码进行测试» «添加单元测试» «添加模糊测试» «修复无效字符串错误» «修复双反错误» «结论» 注意 更多 Go 教程,请参阅 https://go.dev/doc/tutorial/index.html[教程]。 Go fuzzing 当前支持 https://go.dev/security/fuzz/#requirements[Go Fuzzing 文档] 中列出的内置类型的子集,并支持将来添加的更多内置类型。 先决条件 Go 1.18 或更高版本的安装。 有关安装说明,请参阅 https://go.dev/doc/install[安装 Go]。 用于编辑代码的工具。 您拥有的任何文本编辑器都可以正常工作。 一个命令终端。 Go 在 Linux 和 Mac 上的任何终端以及 Windows 中的 PowerShell 或 cmd 上都能很好地工作。 支持模糊测试的环境。 目前仅在 AMD64 和 ARM64 架构上使用覆盖检测进行模糊测试。 [[为您的代码创建一个文件夹]] 为您的代码创建一个文件夹 首先,为您要编写的代码创建一个文件夹。 1、 打开命令提示符并切换到您的主目录。 在 Linux 或 Mac 上: ...

2022-12-19 · 9 min · 1893 words · 老墨

(译)初始Go模糊测试

原文地址: https://go.dev/security/fuzz/ 从 Go 1.18 开始,Go 在其标准工具链中支持模糊测试。Native Go 模糊测试受 https://google.github.io/oss-fuzz/getting-started/new-project-guide/go-lang/#native-go-fuzzing-support[OSS-Fuzz 支持]。 Go模糊测试详细教程见:进入Go模糊测试的世界 一文。 概述 Fuzzing 是一种自动化测试,它不断地操纵程序的输入以查找错误。Go fuzzing 使用覆盖率指导来智能地不断重复执行模糊测试的代码,以发现并向用户报告问题。由于它可以覆盖人类经常错过的边缘情况,因此模糊测试对于发现安全漏洞特别有价值。 下面是一个 «fuzztarget, 模糊测试» 的例子,突出了它的主要组成部分。 上图显示整体模糊测试的示例代码,其中包含一个模糊目标( «corpus, fuzz target» )。 在模糊目标之前调用 f.Add 添加种子语料库,模糊目标的参数高亮显示为fuzzing参数。 编写模糊测试 要求 以下是模糊测试必须遵循的规则。 模糊测试必须是一个形如 FuzzXxx 的函数,以 Fuzz 作为前缀,它只接受一个 *testing.F 参数并且没有返回值。 模糊测试必须在 *_test.go 文件中才能运行。 调用 https://pkg.go.dev/testing#F.Fuzz[(*testing.F).Fuzz] 方法时的匿名函数参数称之为 «fuzztarget, 模糊目标»,形如 func(t *testing.T, xxx)*, 它必须是一个函数,接受一个 *testing.T 作为第一个参数,其他后续参数称为模糊参数,且该函数没有返回值。 每个模糊测试必须只有一个模糊目标。 所有 «seedcoprus, 种子语料库» 条目必须具有与 «fuzzing, 模糊参数» 相同的类型,并且顺序相同。这适用于调用 https://pkg.go.dev/testing#F.Add[(*testing.F).Add] 添加的种子语料库和 testdata/fuzz 目录中已有的语料库文件。 模糊测试参数只能是以下类型: string, []byte int, int8, int16, int32/rune, int64 uint, uint8/byte, uint16, uint32, uint64 float32, float64 bool 建议 以下建议将帮助您充分利用模糊测试。 ...

2022-10-26 · 3 min · 435 words · 老墨