测试覆盖率是度量代码测试详尽程度的指标,它指出了被测试的代码在全部代码中所占的百分比,Go 的 testing
标准库中也提供了测试覆盖率的指标。
我们以 tango.go 文件中的三个函数为测试目标,新建一个文件 tango_coverage_test.go 将其中两个函数进行测试。
package main
import (
"testing"
)
func TestStringFromAssignment(t *testing.T) {
StringFromBuffer(10)
}
func TestStringFromAppendJoin(t *testing.T) {
StringFromAppendJoin(10)
}
在命令行中输入 go test -cover
执行测试并获取测试覆盖率
$ go test -cover -v tango_coverage_test.go tango.go
=== RUN TestStringFromAssignment
--- PASS: TestStringFromAssignment (0.00s)
=== RUN TestStringFromAppendJoin
--- PASS: TestStringFromAppendJoin (0.00s)
PASS
coverage: 66.7% of statements
ok command-line-arguments 0.402s coverage: 66.7% of statements
命令执行结果表明测试都已经通过,但是覆盖率只有 66.7%,并未达到 100%。
ExampleXxx
testing
标准库除了提供测试功能外还提供了验证的功能,验证相关的函数都是以 ExampleXxx
命名的。
新建一个 whiskey.go 文件,输入如下代码:
package main
import "fmt"
func ExampleHallo() {
fmt.Println("Hallo")
// Output: Hallo
}
执行该测试
=== RUN ExampleHallo
--- PASS: ExampleHallo (0.00s)
PASS
根据输出,我们可以确定测试通过了,将注释内容改为 // Output: Hello
再次执行测试。
=== RUN ExampleHallo
--- FAIL: ExampleHallo (0.00s)
got:
Hallo
want:
Hello
FAIL
测试函数包含以 “Output:” 开头的行注释,在运行测试时,Go 会将测试函数的输出和 “Output:” 注释中的值做比较,如果两个值不同等,则测试会执行失败并输出实际结果和 Output
注释中的值。
我们以 zulu.go
中的 Add
函数为例,新建一个 whiskey.go 文件。
// filename: zulu.go
func Add(x, y int) int {
return x + y
}
// filename: whiskey.go
func ExampleAdd() {
res := Add(1, 2)
fmt.Println(res)
// Output: 5
}
执行 whiskey.go 中的测试。
=== RUN ExampleAdd
--- FAIL: ExampleAdd (0.00s)
got:
3
want:
5
FAIL
要注意验证函数的命名一定要符合规范 ExampleXxx
且该函数没有任何参数。
如果输出顺序可能不确定,比如循环输出 map 的值,那么可以使用 “Unordered output:” 开头的注释来作为比较的结果。
testing.T
和 testing.B
的 Run
方法允许定义子单元测试和子基准测试,而不必为它们单独定义函数,并且这些子测试共享通用 setup
和 tear-down
方法。
func TestXxx(t *testing.T) {
t.Run("A=1", func(t *testing.T) {
// 测试代码
})
t.Run("B=2", func(t *testing.T) {
// 测试代码
})
t.Run("C=3", func(t *testing.T) {
// 测试代码
})
}
执行时使用 -run
参数来执行运行的子测试
go test -run '' # 执行所有测试。
go test -run Xxx # 执行匹配 "Xxx" 的顶层测试,例如 "TestXxx"。
go test -run Xxx/A= # 对于匹配 "Xxx" 的顶层测试,执行其匹配 "A=" 的子测试。
go test -run /A=1 # 执行所有匹配 "A=1" 的子测试。