GO(单元)测试的基本规则和流程
文章目录
一、GO程序的三类单元测试
我们可以为Go程序编写三类测试:
- 功能测试(test)
- 基准测试(benchmark,也称性能测试)
- 示例测试(example)
示例测试严格来说是一种功能测试,只不过它更关注程序打印出来的内容。
一个测试源码文件只会针对某个命令源码文件或库源码文件做测试,所以我们总是应该把它们放在同一个代码包内。
测试源码文件的主名称应该以被测源码文件的主名称为前缀,并且以“_test”为后缀。
例如,被测源码文件的名称为 demo01.go, 针对它的测试文件的名称应该为demo01_test.go。
每个测试源码文件都必须至少包含一个测试函数。从语法上讲,每个测试文件都可以包含任何一类测试函数。哪怕把三类测试函数都写进去也是可以的。
二、GO语言对测试函数的名称和签名的规定
- 对于功能测试函数,其名称必须以Test为前缀,并且参数列表只应有一个
*testing.T
类型的参数声明; - 对于性能测试函数,其名称必须以Benchmark为前缀,并且唯一参数的类型必须是
*testing.B
类型的; - 对于示例测试函数来说,其名称必须以Example为前缀,但对函数的参数列表没有强制规定;
三、go test
命令执行的主要测试流程
首先要记住一点,只有测试源码文件的名称对了,测试函数的名称和签名也对了,运行go test
命令的时候,其中的测试代码才有可能被运行。
运行go test
命令:
- 运行
go test
命令在开始运行时,会先做一些准备工作,比如,确定内部需要哪些命令,检查我们指定的代码包或源码文件的有效性,以及判断我们给予的标识是否合法,等等; - 在准备工作顺利完成后,
go test
命令就会针对每个被测试代码包,依次地进行构建、执行包中符合要求的测试函数。清理临时文件,打印测试结果。
为了加快速度,它通常会并发地对多个被测代码包进行功能测试,只不过,最后打印结果的时候,它会依照我们给定的顺序逐个进行,这会让我们感觉到它是在完全串行地执行测试流程。
另一方面,由于并发的测试会让性能测试对结果存在偏差,所以性能测试多是串行进行的。并且下一个代码包的性能测试总会等到上一个代码性能测试的结果打印完才会开始。并且性能测试函数的执行也都是串行的。
四、功能测试的测试结果
(1)测试成功与结果缓存
看测试命令和结果:
$ go test article20/q1
ok article20/q1 0.415s
$ go test article20/q1
ok article20/q1 (cached)
$
连续运行两次,发现第二次运行,打印的内容最右边是“(cached)“ 字样。这是表明,由于测试代码和被测试代码都没有任何变动,所以go test
命令直接把之前缓存测试成功的结果打印出来了。
**go命令通常会缓存程序构建的结果,以便在将来的构建中重用。**可以通过go env GOCACHE
命令查看缓存目录的路径。
一旦有任何变动,缓存数据就会失效,go命令就会再次真正的执行操作。
- 可以运行
go clean -cache
命令,手动删除所有的缓存数据。 - 对于测试成功的结果,go命令也会缓存。可以运行
go clean -testcache
命令,删除所有的测试结果缓存。这样做不会删除任何构建结果缓存。 - 设置环境变量GODEBUG的值,也可以稍微改变go命令的缓存行为。比如,设置值为
gocacheverify=1
将会导致go命令绕过任何的缓存数据,而真正地执行操作并重新生成所有结果,然后再去检查新的结果和现有缓存数据是否一致。
(2) t.Fail()
和t.FailNew()
func TestFail(t *testing.T) {
t.Fail()
// t.FailNow() // 次调用会让当前的测试立刻失效
t.Log("Fail.")
}
添加一个Fail函数,在此运行:
$ go