测试规则与流程

对于程序或软件的测试分为很多种:

  • 单元测试
  • API测试
  • 集成测试
  • 灰度测试

单元测试

单元测试也称为程序员测试,就是程序员本该做的自我检查工作之一。

Go程序提供了丰富的API和工具,可以创建测试源码文件,并为命令源码文件和库源码文件中的程序实体编写测试用例。在Go语言中,一个测试用例往往会由一个或多个函数来代表,大多数情况下,每个测试用例仅用一个测试函数(往往用于描述某个程序实体的某方面功能)就足够了。

Go程序可以编写三类测试:

  • 功能测试(test):
  • 基准测试(benchmark,性能测试):
  • 示例测试(example):也是功能测试的一种,更关注程序打印出来的内容

一般情况下,一个测试源码文件只会针对某个命令源码文件或者库文件做测试,所以应该把它们放在一个代码包中。测试源码文件的主名称以被测源码文件的主名称前导,并且,必须以“_test”为后缀。如demo.godemo_test.go

每个测试源码文件都必须包含一个测试函数,用来做任何一类测试,通常把三类测试都放在一起,把控好测试函数的分组和数量即可。分组依据:

  1. 依据测试函数针对的不同程序实体,把它们分成不同的逻辑组,利用注释以及帮助类的变量或测试函数来做分割
  2. 依据被测源码文件中程序实体的先后顺序,来安排测试源文件中测试函数的顺序

测试函数的名称和签名的规定

  1. 功能测试函数:名称必须以Test为前缀,并且参数列表中只应有一个×testing.T类型的参数声明
  2. 性能测试函数:名称必须以Benchmark为前缀,并且唯一参数的类型必须是×testing.B类型
  3. 示例测试函数:名称必须以Example为前缀,函数的参数列表没有强制规定

go test执行的流程

go test命令运行的前置条件:

  1. 测试源码文件的名称对了
  2. 测试函数名称和签名对了

go test 流程:

  1. 准备工作:确定内部需要用到的命令,检查制定的代码包和源码文件的有效性,判断给予的标记是否合法
  2. 开始执行:针对每个被测试代码包,依次进行构建、执行包中符合要求的测试函数,清理临时文件,打印测试结果

注意是依次,对每个被测代码包go test命令会串行地执行测试流程中的每个步骤。但是为了加快测试速度,通常会并发地对多个被测代码包进行功能测试,只不过在最后打印测试结果的时候,会依照给定的测试逐个进行。并发地测试会让性能测试的结果出现偏差,所以性能测试一般是串行的(只要在所有构建步骤都做完之后,go test命令才会真正开始进行性能测试)

Go语言是一门重视测试的语言,不但自带testing包,还有专用于程序测试的go test命令。要想真正用好一个工具,必须先了解它的核心逻辑

功能测试

// 第一次的测试结果
ok   puzzlers/article20/q2 0.008s

// 第二次的测试结果
ok   puzzlers/article20/q2 (cached)

测试结果分为三个部分:

  1. ok:表示此次测试成功
  2. 被测代码包的导入路径
  3. 对该代码包的测试消耗的时间

再次运行测试命令,在测试结果中第三部分不再显示测试时间,而是显示(cached)。

  • 由于测试代码和被测试代码没有变化,所以go test会直接将缓存测试成功的结果打印出来。
  • 一旦有任何改动,缓存数据失效,go命令再次真正的执行操作。

go 命令通常会缓存程序构建的结果,以便在将来的构建中重用。运行go env GOCACHE命令来查看缓存目录的路径。缓存的数据总是能够正确地放反映出当时的各种源码文件、构建环境、编译器选项等的真实情况。

go 命令会定期清楚最近未使用的缓存数据,执行go clean -cache命令手动删除缓存数据,执行go clean -testcache手动删除所有的测试结果缓存。

设置环境变量GODEBUG的值可以改变go命令的缓存行为。比如设置gocacheverify=1将导致go命令绕过任何的缓存数据,真正的执行操作并重新生成所有结果,然后再去检查新的结果与缓存数据是否一致。

上次修改: 25 November 2019