单元测试
Go 语言测试框架可以让我们很容易地进行单元测试,但是需要遵循下面的规则:
含有单元测试代码的 go 文件必须以
_test.go
结尾,Go 语言测试工具只认符合这个规则的文件。-
单元测试的函数名必须以
Test
开头,是可导出的、公开的函数,测试函数的签名必须接收一个指向testing.T
类型的指针,并且不能返回任何值。func TestFibonacci(t *testing.T) { // ... }
单元测试文件名
_test.go
前面的部分最好是被测试的函数所在的 go 文件的文件名,比如下面示例中单元测试文件叫 main_test.go,因为测试的 Fibonacci 函数在 main.go 文件里。 函数名最好是 Test + 要测试的函数名,比如例子中是 TestFibonacci,表示测试的是 Fibonacci 这个函数。
-
ch/fibonacci.go
package main func Fibonacci(n int) int { if n < 0 { return 0 } if n == 0 { return 0 } if n == 1 { return 1 } return Fibonacci(n-1) + Fibonacci(n-2) }
-
ch/fibonacci_test.go
package main import "testing" func TestFibonacci(t *testing.T) { // 预先定义的一组斐波那契数列作为测试用例(表驱动) caseMap := map[int]int{ 0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5, 6: 8, 7: 13, 8: 21, } for k, v := range caseMap { fib := Fibonacci(k) if v == fib { t.Logf("结果正确:n为%d,值为%d", k, fib) } else { t.Errorf("结果错误:期望%d,但是计算的值是%d", v, fib) } } }
t.Error = Log + Fail
t.Errorf = Logf + Fail
t.Fatal = Log + FailNow
t.Fatalf = Logf + FailNow
运行单元测试:
# go test -v .
=== RUN TestFibonacci
fibonacci_test.go:22: 结果正确:n为0,值为0
fibonacci_test.go:22: 结果正确:n为2,值为1
fibonacci_test.go:22: 结果正确:n为5,值为5
fibonacci_test.go:22: 结果正确:n为6,值为8
fibonacci_test.go:22: 结果正确:n为8,值为21
fibonacci_test.go:22: 结果正确:n为9,值为34
fibonacci_test.go:22: 结果正确:n为1,值为1
fibonacci_test.go:22: 结果正确:n为3,值为2
fibonacci_test.go:22: 结果正确:n为4,值为3
fibonacci_test.go:22: 结果正确:n为7,值为13
--- PASS: TestFibonacci (0.00s)
PASS
ok ch18/main 0.002s
-v
参数会显示每个用例的测试结果。
断言
Go 语言官方库并没有提供断言的功能,官方认为这可能导致用户懒于思考良好的错误处理和汇报。
但没有断言实在是不方便,所以我们可以使用第三方库 testify 中的 assert 包来实现:
package main
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestFibonacci(t *testing.T) {
// 预先定义的一组斐波那契数列作为测试用例(表驱动)
caseMap := map[int]int{
0: 0,
1: 1,
2: 1,
3: 2,
4: 3,
5: 5,
6: 8,
7: 13,
8: 21,
}
for k, v := range caseMap {
fib := Fibonacci(k)
assert.Equal(t, fib, v)
}
}
常用的 assert 有:
- assert.Equal
- assert.NotEqual
- assert.Zero
- assert.NotZero
- assert.Nil
- assert.NotNil
同时 testify 还提供了 require 包,和 assert 包的区别是:require包中断言函数一旦执行失败便会导致测试退出,后续的测试代码将无法继续执行。
子测试
TODO
suite
Go testing包没有引入testsuite(测试套件) 或 testcase(测试用例) 的概念,只有 Test 和 SubTest。testify 的suite包为我们提供了一种基于suite/case 结构组织测试代码的方式。
TODO
运行项目下的所有测试用例
在项目根目录下执行go test ./...
指定运行部分测试
如果只想运行一部分测试,我们可以在命令时指定:
# go test -run TestFibonacci
并且支持部分通配符*
,和部分正则表达式,例如^
,$
测试覆盖率以及发布报告
-cover
参数可以查看覆盖率。
如果想要测试覆盖率的报告,那么首先:
go test test.go -coverprofile=covprofile
接着再使用工具解析上面的报告,将其转换为html结果网页
go tool cover -html=covprofile -o coverage.html
编译测试为可执行文件
有时,我们编写的测试文件,需要在不同的测试机器上运行,那么可以使用
go test -c
将测试编译为可执行文件。
如何调试测试
- 方法一
# dlv test
- 方法二
使用go test -c
将测试编译为可执行文件,然后再使用 dlv 调试。