使用go test测试总结

一、go test

go test命令是一个按照一定的约定和组织来测试代码的程序。在包目录内,所有以_test.go为后缀名的源文件在执行go build时不会被构建成包的一部分,它们是go test测试的一部分。

*_test.go文件中,有三种类型的函数:测试函数基准测试(benchmark)函数示例函数

  • 一个测试函数是以Test为函数名前缀的函数,用于测试程序的一些逻辑行为是否正确;go test命令会调用这些测试函数并报告测试结果是PASS或FAIL。
  • 基准测试函数是以Benchmark为函数名前缀的函数,它们用于衡量一些函数的性能;go test命令会多次运行基准测试函数以计算一个平均的执行时间。
  • 示例函数是以Example为函数名前缀的函数,提供一个由编译器保证正确性的示例文档。

go test命令会遍历所有的*_test.go文件中符合上述命名规则的函数,生成一个临时的main包用于调用相应的测试函数,接着构建并运行、报告测试结果,最后清理测试中生成的临时文件。

二、go test的两种运行模式

cd packagexxx && go test 本地目录模式,即直接运行当前目录下的包,即 packagexxx 目录下的包的测试。

go test ./packagexxx 包列表模式,运行指定包下的测试,./packagexxx 可以指定多个(如 ./a ./b),也可以使用 ./xxx/..../...,测试该目录下的所有包,在该模式下,go test 会使用缓存,可以通过 go clean -testcache 清理缓存,或者通过手动指定 -count 1 来禁用缓存。

三、go test 常用参数

3.1 选择测试目标

-run regexp:运行正则匹配测试函数(测试的函数名须以 Test 开头,测试函数的参数须为 *testing.T)。默认情况下,不运行任何测试。要运行所有测试,请使用 -run .-run=.regexp 会按照不带括号的 / 分割为多个正则表达式,并且测试标识符的每个部分都必须匹配序列中的相应元素。注意,对于 -run=X/Y 这种情况,如果 X 存在 X/Y 不存在,则 X 仍会被执行,因为必须运行 X,才能查找到到 X/Y 是否存在。

-bench regexp:运行正则匹配基准测试(测试的函数名须以 Benchmark 开头,测试函数的参数须为 *testing.B)。

-fuzz regexp:模糊测试的方式,运行 Fuzz 测试,默认情况下不进行模糊测试。指定时,命令行参数必须与主模块中的一个包完全匹配,而正则表达式必须与该包中的一个模糊测试完全匹配 ,模糊测试将在常规测试、基准测试、其他模糊测试的种子语料库和 Example 完成后进行。

-list regexp:列出所有符合正则表达式的顶层测试,不会运行任何测试。

3.2 通用参数

  • -v:可用于打印每个测试函数的名字和运行时间
  • -timeout d:超时时间,默认为 10 分钟 (10m)。
  • -short:告诉长时间运行的测试以缩短它们的运行时间。它默认关闭,但在 all.bash 期间设置,以便安装 Go 树可以运行健全性检查,但不能花时间运行详尽的测试 (这一句不理解,这个 all.bash?) 。
  • -vet list:在测试前调用 go vet
  • -failfast:在第一次测试失败后不要开始新的测试,立即失败。常见的一个测试命令go test -v -short -failfast 2>&1 | tee log
  • -json:以 JSON 格式记录详细输出和测试结果。这提出了与机器可读格式的 -v 标志相同的信息。
  • -parallel n:指 t.Parallel 调用后允许产生的做到并行运行的测试数目。 在进行模糊测试时,该标志的值是可以同时调用模糊函数的最大子进程数,而不管是否调用了 t.Parallel。 默认情况下,-parallel 设置为 GOMAXPROCS 的值。 将 -parallel 设置为高于 GOMAXPROCS 的值可能会由于 CPU 争用而导致性能下降,尤其是在模糊测试时。 请注意,-parallel 仅适用于单个测试二进制文件(包)。 根据 -p 标志的设置,go test 命令也可以并行运行不同包的测试(参见 go help build)。
  • -shuffle off,on,N:随机测试执行顺序,默认为 off,N 为指定一个随机数种子。

3.3 对 -run-bench 匹配的测试的配置

  • -count n,对 -fuzz 不生效。默认为 1 并在包列表模式(测试缓存)。手动指定 1 将禁用测试缓存。该参数仅用来指定测试运行的次数,如果设置了 -cpu,则为每个 GOMAXPROCS 值运行 n 次。
  • -cpu 1,2,4 指定运行测试的 GOMAXPROCS 列表,默认值为当前 GOMAXPROCS 值,每个测试函数会针对每一个 cpu 值运行一次。

3.4 对 -bench 匹配的测试的配置

  • -benchtime t 对每个基准运行足够的迭代以获取指定的 t 作为 time.Duration(例如,-benchtime 1h30s)。默认值为 1 秒 (1s)。特殊语法 Nx 表示运行准 N 次(例如,-benchtime 100x)。
  • -benchmem 打印基准测试的内存分配统计信息。

3.5 对 -fuzz 匹配的测试的配置

  • -fuzztime t-benchtime t 类似。
  • -fuzzminimizetime t-fuzztime t 类似,表示最小值。

3.6 覆盖率相关

  • -cover 启用覆盖率统计
  • -covermode set,count,atomic 设置正在测试的包的覆盖率分析模式。默认值为 set,如果启用 -race,默认值为 atomic
    set: bool: 这个语句是否运行。
    count: int: 这个语句运行了多少次。
    atomic: int: count,但在多线程测试中是精确的;但是代价更高。
  • -coverpkg pattern1,pattern2,pattern3 在每个测试中对匹配模式的包应用覆盖率分析。默认情况下,每个测试只分析正在测试的包。有关包模式的描述,请参阅 go help packages
  • -coverprofile cover.out 在所有测试通过后,将覆盖率配置文件写入的文件。

3.7 性能监控相关(参见:原文)

-blockprofile block.out
-blockprofilerate n
-cpuprofile cpu.out
-memprofile mem.out
-memprofilerate n
-mutexprofile mutex.out
-mutexprofilefraction n
-outputdir directory
-trace trace.out

3.8 编译构建相关标志

  • go help build 相关标志
  • -args 将命令行的其余部分(-args 之后的所有内容)传递给测试二进制文件,未经解释且未更改。 因为这个标志占用了命令行的剩余部分,所以包列表(如果存在)必须出现在这个标志之前。
  • -c 将测试二进制文件编译为 pkg.test 但不要运行它(其中 pkg 是包导入路径的最后一个元素)。 可以使用 -o 标志更改文件名。(eg: go test ./01-testing -c
  • -o file 将测试二进制文件编译到指定文件。测试仍然运行(除非指定了 -c 或 -i)。
  • -exec xprog 使用 xprog 运行测试二进制文件,详见:go help run

四、go test测试举例

package word

import "unicode"
import "testing"

// IsPalindrome reports whether s reads the same forward and backward.
// Letter case is ignored, as are non-letters.
func IsPalindrome(s string) bool {
	var letters []rune
	for _, r := range s {
		if unicode.IsLetter(r) {
			letters = append(letters, unicode.ToLower(r))
		}
	}
	for i := range letters {
		if letters[i] != letters[len(letters)-1-i] {
			return false
		}
	}
	return true
}

func TestIsPalindrome(t *testing.T) {
	var tests = []struct {
		input string
		want  bool
	}{
		{"", true},
		{"a", true},
		{"aa", true},
		{"ab", false},
		{"kayak", true},
		{"detartrated", true},
		{"A man, a plan, a canal: Panama", true},
		{"Evil I did dwell; lewd did I live.", true},
		{"Able was I ere I saw Elba", true},
		{"été", true},
		{"Et se resservir, ivresse reste.", true},
		{"palindrome", false}, // non-palindrome
		{"desserts", false},   // semi-palindrome
	}
	for _, test := range tests {
		if got := IsPalindrome(test.input); got != test.want {
			t.Errorf("IsPalindrome(%q) = %v", test.input, got)
		}
	}
}

以上是一个测试回文数的测试用例,有以下内容需注意:

  1. 每个测试函数必须导入testing包。
  2. 测试函数的名字必须以Test开头,可选的后缀名必须以大写字母开头,如TestMain
  3. 其中t参数用于报告测试失败和附加的日志信息。
  4. 失败测试的输出并不包括调用t.Errorf时刻的堆栈调用信息。和其他编程语言或测试框架的assert断言不同,t.Errorf调用也没有引起panic异常或停止测试的执行。
  5. 如果我们真的需要停止测试,或许是因为初始化失败或可能是早先的错误导致了后续错误等原因,我们可以使用t.Fatal或t.Fatalf停止当前测试函数。它们必须在和测试函数同一个goroutine内调用

你可能感兴趣的:(工具及使用经验,golang)