go test命令用于对Go语言编写的程序进行测试.这种测试是以代码包为单位的.当然,这还需要测试源码文件的帮助.关于怎样编写并写好Go程序测试代码,我们会在本章的第二节加以详述.在这里,我们只讨论怎样使用命令启动测试.

go test命令会自动测试每一个指定的代码包.当然,前提是指定的代码包中存在测试源码文件.关于测试源码文件方面的知识,在我的图书<Go并发编程实战>中有详细介绍.测试源码文件是名称以"_test.go"为后缀的\内含若干测试函数的源码文件.测试函数一般是以"Test"为名称前缀并有一个类型为"testing.T"的参数声明的函数.

现在,我们来测试goc2p项目中的几个代码包.在使用go test命令时指定代码包的方式与其他命令无异——使用代码包导入路径.如果需要测试多个代码包,则需要在它们的导入路径之间加入空格以示分隔.示例如下:

hc@ubt:~$ go test basic cnet/ctcp pkgtool
ok  	basic	0.012s
ok  	cnet/ctcp	2.014s
ok  	pkgtool	0.014s

go test命令在执行完所有的代码包中的测试文件之后,会以代码包为单位打印出测试概要信息.在上面的示例中,对应三个代码包的三行信息的第一列都是"ok".这说明它们都通过了测试.每行的第三列显示运行相应测试所用的时间,以秒为单位.我们还可以在代码包目录下运行不加任何参数的运行go test命令.其作用和结果与上面的示例是一样的.

另外,我们还可以指定测试源码文件来进行测试.这样的话,go test命令只会执行指定文件中的测试,像这样:

	hc@ubt:~/golang/goc2p/src/pkgtool$ go test envir_test.go
# command-line-arguments
./envir_test.go:25: undefined: GetGoroot
./envir_test.go:40: undefined: GetAllGopath
./envir_test.go:81: undefined: GetSrcDirs
./envir_test.go:83: undefined: GetAllGopath
./envir_test.go:90: undefined: GetGoroot
FAIL	command-line-arguments [build failed]

我们看到,与指定源码文件进行编译或运行一样,命令程序会为指定的源码文件生成一个虚拟代码包——"command-line-arguments".但是,测试并没有通过.但其原因并不是测试失败,而是编译失败.对于运行这次测试的命令程序来说,测试源码文件envir_test.go是属于代码包"command-line-arguments"的.并且,这个测试源码文件中使用了库源码文件envir.go中的函数.但是,它却没有显示导入这个库源码文件所属的代码包.这显然会引起编译错误.如果想解决这个问题,我们还需要在执行命令时加入这个测试源码文件所测试的那个源码文件.示例如下:

hc@ubt:~/golang/goc2p/src/pkgtool$ go test envir_test.go envir.go
ok  	command-line-arguments	0.010s

现在,我们故意使代码包pkgtool中的某个测试失败.现在我们再来运行测试:

hc@ubt:~$ go test basic cnet/ctcp pkgtool
ok      basic   0.010s
ok      cnet/ctcp       2.015s
--- FAIL: TestGetSrcDirs (0.00 seconds)
        envir_test.go:85: Error: The src dir &#039;/usr/local/go/src/pkg&#039; is incorrect.
FAIL
FAIL    pkgtool 0.009s

我们通过以上示例中的概要信息获知,测试源码文件中envir_test.go的测试函数TestGetSrcDirs中的测试失败了.在包含测试失败的测试源码文件名的那一行信息中,紧跟测试源码文件名的用冒号分隔的数字是错误信息所处的行号,在行号后面用冒号分隔的是错误信息.这个错误信息的内容是用户自行编写的.另外,概要信息的最后一行以"FAIL"为前缀.这表明针对代码包pkgtool的测试未通过.未通过的原因在前面的信息中已有描述.

一般情况下,我们会把测试源码文件与被测试的源码文件放在同一个代码包中.并且,这些源码文件中声明的包名也都是相同的.除此之外我们还有一种选择,那就是测试源码文件中声明的包名可以是所属包名再加"_test"后缀.我们把这种测试源码文件叫做包外测试源码文件.不过,包外测试源码文件存在一个弊端,那就是在它们的测试函数中无法测试被测源码文件中的包级私有的程序实体,比如包级私有的变量\函数和结构体类型.这是因为这两者的所属代码包是不相同的.所以,我们一般很少会编写包外测试源码文件.

关于标记

go test命令的标记处理部分是庞大且繁杂的,以至于使Go语言的开发者们不得不把这一部分的逻辑从go test命令程序主体中分离出来并建立单独的源码文件.因为go test命令中包含了编译动作,所以它可以接受可用于go build命令的所有标记.另外,它还有很多特有的标记.这些标记的用于控制命令本身的动作,有的用于控制和设置测试的过程和环境,还有的用于生成更详细的测试结果和统计信息.

可用于go test命令的几个比较常用的标记是-c`-i-o.这两个就是用于控制go test`命令本身的动作的标记.详见下表.

表0-6 go test命令的标记说明

标记名称 标记描述
-c 生成用于运行测试的可执行文件,但不执行它.这个可执行文件会被命名为"pkg.test",其中的"pkg"即为被测试代码包的导入路径的最后一个元素的名称.
-i 安装/重新安装运行测试所需的依赖包,但不编译和运行测试代码.
-o 指定用于运行测试的可执行文件的名称.追加该标记不会影响测试代码的运行,除非同时追加了标记-c-i.

上述这几个标记可以搭配使用.搭配使用的目的可以是让go test命令既安装依赖包又编译测试代码,但不运行测试.也就是说,让命令程序跑一遍运行测试之前的所有流程.这可以测试一下测试过程.注意,在加入-c标记后,命令程序会把用于运行测试的可执行文件存放到当前目录下.