go test
概述
我们可以为 Go 程序编写三类测试,即:功能测试(test)、基准测试(benchmark,也称性能测试),以及示例测试(example)
测试源码文件的主名称应该以被测源码文件的主名称为前导,并且必须以“_test”为后缀。例如,如果被测源码文件的名称为 demo52.go,那么针对它的测试源码文件的名称就应该是 demo52_test.go。
Go 语言对测试函数的名称和签名都有哪些规定?
- 对于功能测试函数来说,其名称必须以Test为前缀,并且参数列表中只应有一个*testing.T类型的参数声明。
- 对于性能测试函数来说,其名称必须以Benchmark为前缀,并且唯一参数的类型必须是*testing.B类型的。
- 对于示例测试函数来说,其名称必须以Example为前缀,但对函数的参数列表没有强制规定。
测试流程
go test命令就会针对每个被测代码包,依次地进行构建、执行包中符合要求的测试函数,清理临时文件,打印测试结果。这就是通常情况下的主要测试流程。
输入了go test puzzlers/article20/q2,这表示我想对导入路径为puzzlers/article20/q2的代码包进行测试。
功能测试
t.Log方法以及t.Logf方法的作用,就是打印常规的测试日志,只不过当测试成功的时候,go test命令就不会打印这类日志了。如果你想在测试结果中看到所有的常规测试日志,那么可以在运行go test命令的时候加入标记-v。
若我们想让某个测试函数在执行的过程中立即失败,则可以在该函数中调用t.FailNow方法。我在下面把TestFail函数中的t.Fail()改为t.FailNow()。与t.Fail()不同,在t.FailNow()执行之后,当前函数会立即终止执行。
如果你想在测试失败的同时打印失败测试日志,那么可以直接调用t.Error方法或者t.Errorf方法。前者相当于t.Log方法和t.Fail方法的连续调用
性能测试
在运行go test命令的时候加了两个标记。
第一个标记及其值为-bench=.,只有有了这个标记,命令才会进行性能测试
。该标记的值.表明需要执行任意名称的性能测试函数,当然了,函数名称还是要符合 Go 程序测试的基本规则的。
第二个标记及其值是-run=^$,这个标记用于表明需要执行哪些功能测试函数,这同样也是以函数名称为依据的。该标记的值^$意味着:只执行名称为空的功能测试函数,换句话说,不执行任何功能测试函数。 如果运行go test命令的时候不加-run标记,那么就会使它执行被测代码包中的所有功能测试函数。(可是我们现在不想测试功能测试,只想性能测试)
$ go test -bench=. -run=^$ puzzlers/article20/q3
goos: darwin
goarch: amd64
pkg: puzzlers/article20/q3
BenchmarkGetPrimes-8 500000 2314 ns/op
PASS
ok puzzlers/article20/q3 1.192s
核心数
BenchmarkGetPrimes-8被称为单个性能测试的名称,它表示命令执行了性能测试函数BenchmarkGetPrimes,并且当时所用的最大 P 数量为8。 最大 P 数量相当于可以同时运行 goroutine 的逻辑 CPU 的最大个数。这里的逻辑 CPU,也可以被称为 CPU 核心,但它并不等同于计算机中真正的 CPU 核心,只是 Go 语言运行时系统内部的一个概念,代表着它同时运行 goroutine 的能力。
顺便说一句,一台计算机的 CPU 核心的个数,意味着它能在同一时刻执行多少条程序指令,代表着它并行处理程序指令的能力。
我们可以通过调用 runtime.GOMAXPROCS函数改变最大 P 数量,也可以在运行go test命令时,加入标记-cpu来设置一个最大 P 数量的列表,以供命令在多次测试时使用。
-cpu的值应该是一个正整数的列表,比如1,2,4。针对于此值中的每一个正整数,go test命令都会先设置最大 P 数量为该数,然后再执行测试函数。
go test命令会先以1,2,4为最大 P 数量分别去执行第一个测试函数,之后再用同样的方式执行第二个测试函数,以此类推。
执行次数
它指的是被测函数的执行次数,而不是性能测试函数的执行次数。 go test命令在执行性能测试函数的时候会给它一个正整数,若该测试函数的唯一参数的名称为b,则该正整数就由b.N代表。我们应该在测试函数中配合着编写代码,比如:
for i := 0; i < b.N; i++ {
GetPrimes()
}
go test命令会先尝试把b.N设置为1,然后执行测试函数。如果测试函数的执行时间没有超过上限,此上限默认为 1 秒,那么命令就会改大b.N的值,然后再次执行测试函数,如此往复,直到这个时间大于或等于上限为止。
当某次执行的时间大于或等于上限时,我们就说这是命令此次对该测试函数的最后一次执行。这时的b.N的值就会被包含在测试结果中,也就是上述测试结果中的500000。
参数
go test 后面可以跟参数:
-cpu p的数量,可以是个列表,如果不设置默认是机器核心数
-count标记是专门用于重复执行测试函数的。它的值必须大于或等于0,并且默认值为1。 如果我们在运行go test命令的时候追加了-count 5,那么对于每一个测试函数,命令都会在预设的不同条件下(比如不同的最大 P 数量下)分别重复执行五次。 注意:这是测试函数的执行数量,不是被测试函数
-benchmem 输出基准测试的内存分配统计信息。
-benchtime 用于指定基准测试的探索式测试执行时间上限
-coverprofile=xxxx.out 输出覆盖率的out文件,使用go tool cover -html=xxxx.out 命令转换成Html的覆盖率测试报告。 覆盖率测试将被测试的代码拷贝一份,在每个语句块中加入bool标识变量,测试结束后统计覆盖率并输出成out文件,因此性能上会有一定的影响。