go test 工具
go test 子命令是Go 语言包的测试驱动程序,这些包根据某些约定组织在一起。在一个包木目录中,以_test.go 结尾的文件不是 go build 命令编译的目标,而是 go test 编译的目标。
在 *_test.go 文件中,三种函数需要特殊对待,即功能测试函数、基准测试函数和示例函数。功能测试函数是以Test 前缀命名的函数,用来检测一些程序逻辑的正确性,go test 运行测试函数,并且报告结果是 PASS 还是 FAIL。基准测试函数的名称以Benchmark 开头,用来测试某些操作的性能,go test 汇报操作的平均执行时间。示例函数的名称,以Example 开头,用来提供机器检查过的文档。
Test 函数
package main
import "testing"
func TestPalindrome(t *testing.T) {
if !IsPalindrome("detartrated") {
t.Errorf(`IsPalindrome("detartrated") = false`)
}
if !IsPalindrome("kayak") {
t.Errorf(`IsPalindrome("kayak") = false`)
}
}
func TestFrenchPalindrome(t *testing.T) {
if !IsPalindrome("french") {
t.Errorf(`IsPalindrome("french") = false`)
}
}
func TestCanalPalindrome(t *testing.T) {
input := "A man,a plan, a canal: Panama"
if !IsPalindrome(input) {
t.Errorf(`IsPalindrome(%q) = false`, input)
}
}
func IsPalindrome(s string) bool {
for i := range s {
if s[i] != s[len(s) - i - 1] {
return false
}
}
return true
}
将上面的代码保存到文件 *_.test.go 文件中。
执行 go test 命令即可。
go test -v 可以输出包中每个测试用例的名称和执行的时间。
选项 -run 的参数是一个正则表达式,它可以使得 go test 只运行那些测试函数名称匹配给定模式的函数。
go test -v -run=“French|Canal”
我们可以使用 go list 工具来汇总一个包目录中哪些是产品代码,哪些是保内测试以及哪些是外部测试。我们用 fmt 包来做例子。GoFiles 是包含产品代码的文件列表,这些文件是go build 命令将编译进你程序的代码。
go list -f={{.GoFiles}} fmt
TestGoFiles 也是获取属于 fmt 包的文件列表,但是这些是以 _test.go 结尾的文件仅在编译测试的时候才会使用。
go list -f={{.TestGoFiles}} fmt
[export_test.go]
XTestGoFiles 是包外部测试文件列表
go list -f={{.XTestGoFiles}} fmt
[example_test.go fmt_test.go gostringer_example_test.go scan_test.go stringer_example_test.go stringer_test.go]
覆盖率
go test -coverprofile=c.out
-coverprofile 这个标记通过检测产品代码,启用了覆盖数据收集。也就是说,它修改了源代码的副本,这样在每个语句块在执行前,设置一个布尔变量,每个语句块都对应一个变量。在修改的程序退出之前,它将每个变量的值都写入指定的 c.out 日志文件中并且输出被执行的语句的汇总信息(如果只要汇总信息的话,可以执行命令 go test -cover)
如果 go test 命令指定了 -convermode=count 标记,每个语句块的检测会递增一个计数器而不是设置布尔变量。由此可识别出执行频率较高的“热块”或者相反的“冷块”。
go tool cover -html=c.out
上面的命令会运行 cover 工具,来处理生成的日志,生成一个 HTML 报告,并在一个新的浏览器窗口打开它。
Benchmark 函数
package main
import "testing"
func BenchmarkIsPalindrome(b *testing.B) {
for i := 0; i < b.N; i++ {
IsPalindrome("A man, a plan, a canal: Panama")
}
}
func IsPalindrome(s string) bool {
for i := range s {
if s[i] != s[len(s) - i - 1] {
return false
}
}
return true
}
这里是 IsPalindrome 函数的基准测试,它在一个循环中调用了 IsPalindrome 共 N 次。
标记 -bench 的参数指定了要运行的基准测试。它是一个匹配 Benchmark 函数名称的正则表达式,它的默认值不匹配任何函数。模式“.” 使它匹配包中所有的基准测试函数,因为这里只有一个基准测试函数,所以和指定 -bench=IsPalindrome 效果一样。
go test -bench=.
基准测试名称的数字8标识 GOMAXPROCS 的值,这个对并发基准测试很重要。
报告告诉我们每次IsPalindrome 调用耗费2.54ns,这个是1000000000 次调用的平均值。
命令行 -benchmem 在报告中报告了内存分配统计数据。
go test -bench=. -benchmem