Go 编程实例【测试】
阅读目录
- 基础实例
- 组织你的单元测试代码
- 关于 go testing 启动命令
基础实例
想要写出好的 Go 程序,单元测试是很重要的一部分。
testing 包为提供了编写单元测试所需的工具,写好单元测试后,我们可以通过 go test 命令运行测试。
为方便演示,例子的代码位于 main 包,实际上,单元测试的代码可以位于任何包下。
测试代码通常与需要被测试的代码位于同一个包下。
// main_test.go
package main
import (
"fmt"
"testing"
)
// 我们要测试下面这个简单的函数——返回最小值。
// 一般地,需要被测试的代码应该在类似于 `intutils.go` 的文件下,
// 其对应的测试文件应该被命名为 `intutils_test.go`。
func IntMin(a, b int) int {
if a < b {
return a
} else {
return b
}
}
// 通常编写一个名称以 `Test` 开头的函数来创建测试。
func TestIntMinBasic(t *testing.T) {
ans := IntMin(2, -2)
if ans != -2 {
// `t.Error*` 会报告测试失败的信息,然后继续运行测试。
// `t.Fail*` 会报告测试失败的信息,然后立即终止测试。
t.Errorf("IntMin(2, -2) = %d; want -2", ans)
}
}
// 单元测试可以重复,所以会经常使用 *表驱动* 风格编写单元测试,
// 表中列出了输入数据,预期输出,使用循环,遍历并执行测试逻辑。
func TestIntMinTableDriven(t *testing.T) {
var tests = []struct {
a, b int
want int
}{
{
0, 1, 0},
{
1, 0, 0},
{
2, -2, -2},
{
0, -1, -1},
{
-1, 0, -1},
}
for _, tt := range tests {
// t.Run 可以运行一个 "subtests" 子测试,一个子测试对应表中一行数据。
// 运行 `go test -v` 时,他们会分开显示。
testname := fmt.Sprintf("%d,%d", tt.a, tt.b)
t.Run(testname, func(t *testing.T) {
ans := IntMin(tt.a, tt.b)
if ans != tt.want {
t.Errorf("got %d, want %d", ans, tt.want)
}
})
}
}
使用 -v 参数查看详细信息:
[root@bogon test]# go test -v
=== RUN TestIntMinBasic
--- PASS: TestIntMinBasic (0.00s)
=== RUN TestIntMinTableDriven
=== RUN TestIntMinTableDriven/0,1
=== RUN TestIntMinTableDriven/1,0
=== RUN TestIntMinTableDriven/2,-2
=== RUN TestIntMinTableDriven/0,-1
=== RUN TestIntMinTableDriven/-1,0
--- PASS: TestIntMinTableDriven (0.00s)
--- PASS: TestIntMinTableDriven/0,1 (0.00s)
--- PASS: TestIntMinTableDriven/1,0 (0.00s)
--- PASS: TestIntMinTableDriven/2,-2 (0.00s)
--- PASS: TestIntMinTableDriven/0,-1 (0.00s)
--- PASS: TestIntMinTableDriven/-1,0 (0.00s)
PASS
ok test 0.002s
[root@bogon test]#
组织你的单元测试代码
- 测试代码文件名 xxx_test.go,必须遵守。
- 测试函数签名 TestXXX(t *testing.T),必须遵守。
- 测试文件所在包,不强制。可以与对应的功能代码文件位于同一个包,开发者根据自己的需要来确定工程规范。
为了更好的管理单元测试代码,按照 go testing 的命名规范,运行 go testing 会扫描并编译运行工程目录下 xxx_test.go 代码文件中的 TestXXX 测试函数。对一个没有任何测试代码的 go 程序工程运行 go testing 只会提示 no tests to run 并不会报错。
不用担心这些测试代码管理会让你的代码工程变得混乱,你可以使用一个专门的工程级目录(比如叫 test) 来存放所有主要的测试代码。也可以在对应的包(比如 app)下使用对应测试包(比如 app_test)。这样就可以利用人为区分,用何种目录方式完全取决于你的需要。但这对于 go 工具链来说不是必要的,因为它并不会把这些测试代码打包到程序的发行版本中。
关于 go testing 启动命令
在上面的例子中,单元测试用例的启动都是使用 go test
来启动的,关于这个命令,有必要说明的地方。
go test .
仅从当前目录查找 xxx_test.go 测试代码。
go test ./...
找出当前的目录以及子目录下所的 xxx_test.go 测试代码。
go test ./xxx/xxx
找出路径下的 xxx_test.go 测试代码,如果包含子目录,使用 ./xxx/xxx/...
,即在路径后加上 /...
,注意,是 3 个 “.” 号。
go test 路径 -v
-v 参数,打开终端信息打印的开关。
在没有 -v 选项时,测试代码中的打印函数(t.Log、t.Skip、t.Error、t.Fatal)向终端打印的信息,只有测试函数状态为 FAIL 的才会显示。而 fmt.Print
只会在任一测试函数为 FAIL 时,信息才会显示。所以在调试单元测试代码时,通常会使用 -v 参数,可多次成功执行的,不带 -v,以保持终端信息提示的清晰。
这只是实践建议,是否使用取决于你。
go test -run ^TestXXXX$
-run 用来指定执行某个 TestXXX 单元测试函数,支持使用正则表达式来匹配测试函数名称。当然,像 TestMain、init() 这类框架性代码仍然会被执行,以确保环境正确。
还没有评论,来说两句吧...