Go 博客

模糊测试已进入 Beta 阶段

Katie Hockman 和 Jay Conrod
2021 年 6 月 3 日

我们很高兴地宣布,原生模糊测试已准备好进行尖端版本的 Beta 测试!

模糊测试是一种自动化测试类型,它持续地操纵程序的输入以查找诸如恐慌或错误等问题。这些半随机数据变异可以发现现有单元测试可能错过的新的代码覆盖率,并发现其他情况下会被忽略的边缘情况错误。由于模糊测试可以触及这些边缘情况,因此模糊测试对于查找安全漏洞和弱点特别有价值。

有关此功能的更多详细信息,请参阅 golang.org/s/draft-fuzzing-design

入门

要开始使用,您可以运行以下命令:

$ go install golang.org/dl/gotip@latest
$ gotip download

这将从主分支构建 Go 工具链。运行此命令后,gotip 可以作为 go 命令的直接替换。您现在可以运行以下命令:

$ gotip test -fuzz=Fuzz

编写模糊测试

模糊测试必须位于 *_test.go 文件中,作为 FuzzXxx 形式的函数。此函数必须传递一个 *testing.F 参数,就像 *testing.T 参数传递给 TestXxx 函数一样。

以下是一个模糊测试示例,它正在测试 net/url 包 的行为。

//go:build go1.18
// +build go1.18

package fuzz

import (
    "net/url"
    "reflect"
    "testing"
)

func FuzzParseQuery(f *testing.F) {
    f.Add("x=1&y=2")
    f.Fuzz(func(t *testing.T, queryStr string) {
        query, err := url.ParseQuery(queryStr)
        if err != nil {
            t.Skip()
        }
        queryStr2 := query.Encode()
        query2, err := url.ParseQuery(queryStr2)
        if err != nil {
            t.Fatalf("ParseQuery failed to decode a valid encoded query %s: %v", queryStr2, err)
        }
        if !reflect.DeepEqual(query, query2) {
            t.Errorf("ParseQuery gave different query after being encoded\nbefore: %v\nafter: %v", query, query2)
        }
    })
}

您可以在 pkg.go.dev 上阅读有关模糊测试的更多信息,包括 使用 Go 进行模糊测试的概述testing.F 类型的 godoc

预期

这是一项仍在 Beta 阶段的新功能,因此您应该预期会出现一些错误和功能集不完整的情况。查看 标记为“fuzz”的问题跟踪器,以随时了解现有错误和缺少的功能。

请注意,模糊测试可能会消耗大量内存,并且在运行时可能会影响您机器的性能。go test -fuzz 默认情况下会并行在 $GOMAXPROCS 个进程中运行模糊测试。您可以通过使用 go test 显式设置 -parallel 标志来降低模糊测试时使用的进程数。如果您想了解更多信息,请通过运行 gotip help testflag 阅读 go test 命令的文档。

还要注意,模糊测试引擎会将扩展测试覆盖范围的值写入 $GOCACHE/fuzz 中的模糊缓存目录。目前对写入模糊缓存的文件数量或总字节数没有限制,因此它可能会占用大量存储空间(例如,几个 GB)。您可以通过运行 gotip clean -fuzzcache 来清除模糊缓存。

下一步是什么?

此功能将从 Go 1.18 开始可用。

如果您遇到任何问题或有功能建议,请 提交问题

有关该功能的讨论和一般反馈,您也可以参与 Gophers Slack 中的 #fuzzing 频道

模糊测试愉快!

下一篇文章: Stack Overflow 上的 Go 集体
上一篇文章: 2020 年 Go 开发者调查结果
博客索引