golang提供了极为简洁的编写单元测试的方式,只需几行代码,即可轻松创建出一个测试用例,并且可以直接运行。
1.testing单元测试
testinggo test
func TestXXX(t *testing.T)
*testing.T
下面是一个简单的待测试待函数(funcs1.go):
package unit_1
//编写一个简单的方法
func Sum(arr []int) int {
sum := 0
for v := range arr { //故意写错的..
sum += v
}
return sum
}
另外创建一个文件(funcs1_test.go)包含以下测试方法:
package unit_1
import (
"testing"
)
func TestSum(t *testing.T) {
testArr := []int{1, 3, 5, 7}
expected := 16
actual := Sum(testArr)
if actual != expected {
t.Errorf("sum result error.input:%+v expected:%d actual:%d", testArr, expected, actual)
}
}
使用如下命令执行测试操作:
go test .
结果如下:
--- FAIL: TestSum (0.00s)
funcs1_test.go:13: sum result error.input:[1 3 5 7] expected:16 actual:6
FAIL
FAIL testAnything/unit_1 0.006s
发现测试失败,说明函数存在bug。
原因是for range 单参数获取的是索引值,而我们需要的是每个数组元素的值,改正后再次运行可以发现:
ok testAnything/unit_1 0.005s
这次运行成功了!!
2.func TestMain(m *testing.M)
若被测试的方法依赖某些环境,需要首先初始化环境,测试结束后,又需要做清理工作(例如关闭连接)等等可以用TestMain()。如下:
func TestMain(m *testing.M) {
fmt.Println("init anything env....")
m.Run()
fmt.Println("handle close etc..")
}
go test -v
init anything env....
=== RUN TestSum
--- PASS: TestSum (0.00s)
PASS
handle close etc..
ok testAnything/unit_1 0.008s
3.介绍下go test的几个常用的参数:
-bench regexp-cover-run regexp-v
4.使用goland简化上述过程
使用goland可以快速构建测试用例,并且可以替代go test命令执行对应测试方法(本质其实还是go test,只不过交给了goland隐式的调用了)
还是以上面的sum方法为例:
Step.1 在需要测试的方法名出右键-> Generate…
Step.2 选择“Test for Function”
【注】:可能会出现以下提示,选择安装即可
之后会生成如下的代码:
func TestSum(t *testing.T) {
type args struct {
arr []int
}
tests := []struct {
name string
args args
want int
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Sum(tt.args.arr); got != tt.want {
t.Errorf("Sum() = %v, want %v", got, tt.want)
}
})
}
}
nameargswant
func TestSum(t *testing.T) {
type args struct {
arr []int
}
tests := []struct {
name string
args args
want int
}{
// TODO: Add test cases.
{
name: "case1",
args: args{arr: []int{1, 2, 3, 4, 5, 6, 7}},
want: 28,
},
{
name: "case2",
args: args{arr: []int{1, 2, 3, 4, 5, 6}},
want: 22, //故意写错的,模拟测试失败
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Sum(tt.args.arr); got != tt.want {
t.Errorf("Sum() = %v, want %v", got, tt.want)
}
})
}
}
测试结果如下:
init anything env....
=== RUN TestSum
--- FAIL: TestSum (0.00s)
=== RUN TestSum/case1
--- PASS: TestSum/case1 (0.00s)
=== RUN TestSum/case2
--- FAIL: TestSum/case2 (0.00s)
funcs1_test.go:49: Sum() = 21, want 22
FAIL
handle close etc..
Process finished with exit code 0
|–进阶---->
1、单元测试会用的其他的方法:
f
方法名 | 作用 |
---|---|
Log、Logf | 输出信息 |
Fail、Failf | 测试失败,测试终止,相当于 Logf + FailNow |
FailNow | 测试失败,并终止测试 |
Error、Errorf | 标示出现错误,并会继续测试,相当于 Log + Fail |
Skip、Skipf | 相当于 Log[f] + SkipNow |
SkipNow | 跳过测试,测试中断 |
runtime.Goexit()
2、子测试
如果需要在一个测试方法中运行另一个测试方法,可以使用子测试:
func TestSum(t *testing.T) {
type args struct {
arr []int
}
tests := []struct {
name string
args args
want int
}{
// TODO: Add test cases.
{
name: "case1",
args: args{arr: []int{1, 2, 3, 4, 5, 6, 7}},
want: 28,
},
{
name: "case2",
args: args{arr: []int{1, 2, 3, 4, 5, 6}},
want: 21, //故意写错的,模拟测试失败
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Sum(tt.args.arr); got != tt.want {
t.Errorf("Sum() = %v, want %v", got, tt.want)
}
})
}
t.Run("sub Testing", TestSum2)
}
func TestSum2(t *testing.T) {
fmt.Println("do something...")
}
全部方法测试通过才算PASS
init anything env....
=== RUN TestSum
--- PASS: TestSum (0.00s)
=== RUN TestSum/case1
--- PASS: TestSum/case1 (0.00s)
=== RUN TestSum/case2
--- PASS: TestSum/case2 (0.00s)
=== RUN TestSum/sub_Testing
do something...
--- PASS: TestSum/sub_Testing (0.00s)
PASS
handle close etc..