Go 与测试与 Coverage 笔记 | 青训营笔记

117 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 13 天。

本文以 CC-BY-SA 4.0 发布。

Go 与测试

越来越多的语言对单元测试提供了内置的支持, 包括 Rust 的 #[test] 或是 Go 的 func TestXxx(t *testing.T)

go test 测试流程

Go test 根据文件名来识别测试代码。 运行测试时,文件名以 _test.go 结尾的文件会被看作是测试文件 (文件名以 _ 或是以 . 开头的文件会被忽略), 一个包里的所有 *_test.go 文件会被编译成为一个单独的可执行文件。

测试文件里可以有不同种类的函数,对应不同种类的测试:

  • func TestXxx(t *testing.T): 函数名以 Test 开头,会被看作单元测试测例。
  • func BenchmarkXxx(b *testing.B): 基本同上,会被看作性能测试测例。
  • func FuzzXxx(f *testing.F): Fuzzing, 大体是随机生成一大堆数据来找 bug 的一个手段。
  • func ExamplePrintln(): 通过标准输出来进行测试结果判断的测试,会被 godoc 整合至文档里。

还有一个特殊的函数:

  • func TestMain(m *testing.M): 在测试的主 goroutine 上运行的代码(每个包可以有最多一个), 可以用来进行各种初始化,例如打开一个基于内存的 Sqlite 然后进行迁移。

go test 的执行有两种模式:

  • 当前目录模式:go test: 运行当前目录里的测试,测试结果不会缓存起来。

  • 包列表模式:go test 包1 包2 ...: 运行指定包的测试,测试结果会进行缓存 (代码不发生变动的话,测试会直接报之前的结果,不会重新运行)。

    我们可以使用 ./... 来让 Go test 递归测试所有子目录里的包。

Go 1.18 引入了 workspace,但是测试似乎还不能直接在 workspace 根目录下运行: go test ./... 无效。 有一个相关的 issue, 可能之后 go test 或是 go mod tidy 会更轻松一些。

Coverage

Coverage 就是测试的覆盖率。 一个 issue 总结了目前 Go 对 coverage 的支持:

  • go test -coverprofile=<filename> [package target(s)]: 测试对应的包,并把 coverage 结果输出到指定的 <filename> 文件。
  • go tool cover -html=<covdatafile>: 查看对应的文件。

但是,例如在微服务下,我们有可能想要得到集成测试下的覆盖率结果, 但 Go 目前对此的支持并不乐观。 目前我们大概只能用七牛推出的 goc 来比较方便地得到这方面的 coverage 结果。