Go 博客

模糊测试已可进行 Beta 测试

Katie Hockman 和 Jay Conrod
2021 年 6 月 3 日

我们很高兴地宣布,原生模糊测试已可在 tip 分支上进行 beta 测试!

模糊测试是一种自动化测试,它持续地操纵程序的输入以发现诸如 panic 或 bug 之类的问题。这些半随机的数据变异可以发现现有单元测试可能遗漏的新代码覆盖范围,并发现否则会被忽略的边缘情况 bug。由于模糊测试可以触及这些边缘情况,因此模糊测试对于发现安全漏洞和脆弱性特别有价值。

请参阅 golang.org/s/draft-fuzzing-design 了解此功能的更多详细信息。

入门

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

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

这将从 master 分支构建 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 阶段的新功能,因此您应该预料到存在一些 bug 和不完整的功能集。请查看标记为“fuzz”的问题跟踪器,以了解现有 bug 和缺失功能的最新情况。

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

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

下一步是什么?

此功能将在 Go 1.18 版本中开始提供。

如果您遇到任何问题或对某个功能有想法,请提交一个 issue

如需讨论和提供此功能的总体反馈,您还可以参与 Gophers Slack 中的#fuzzing 频道

祝您模糊测试愉快!

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