Golang之单元测试

golang提供了极为简洁的编写单元测试的方式,只需几行代码,即可轻松创建出一个测试用例,并且可以直接运行。

1.testing单元测试

使用testing可以提供自动化的测试支持,通过go test 命令能够执行形如一下结构的函数:

func TestXXX(t *testing.T)

XXX可以是任何的字符串,通常为被测试的方法名。
其中的*testing.T包含测试打印测试日志、输出断言错误等的一些方法,此外还包括Skip用于跳过某个测试用例的方法。

下面是一个简单的待测试待函数(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 执行相应的 benchmarks,例如 -bench=.
-cover 开启测试覆盖率
-run regexp 只运行 regexp 匹配的函数,例如 -run=Array 那么就执行包含有 Array 开头的函数
-v 显示测试的详细命令

4.使用goland简化上述过程

使用goland可以快速构建测试用例,并且可以替代go test命令执行对应测试方法(本质其实还是go test,只不过交给了goland隐式的调用了)
还是以上面的sum方法为例:
Step.1 在需要测试的方法名出右键-> Generate…
Step1
Step.2 选择“Test for Function”
Step2
【注】:可能会出现以下提示,选择安装即可
tips
之后会生成如下的代码:

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)
			}
		})
	}
}

Step.4 在// TODO: Add test cases.处 添加测试用例即可!
其中:
name为测试的名称,可以写序号或者对应测试用例的特点或描述。
args为方法入参,
want因返回值类型会有不同,也就是期望的值。
填好后如下:

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、单元测试会用的其他的方法:

【以下方法中均会打印测试log,其中带f的是格式化的,语法参考fmt包,与printf类似】

方法名作用
Log、Logf输出信息
Fail、Failf测试失败,测试终止,相当于 Logf + FailNow
FailNow测试失败,并终止测试
Error、Errorf标示出现错误,并会继续测试,相当于 Log + Fail
Skip、Skipf相当于 Log[f] + SkipNow
SkipNow跳过测试,测试中断

**【注】**当一个测试的测试函数返回时,又或者当一个测试函数调用 FailNow、 Fatal、Fatalf、SkipNow、Skip 或者 Skipf 中的任意一个时,该测试即宣告结束,只能在运行测试函数的 goroutine 中调用。上述方法是通过调用 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..

Pass!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值