大家好,我是李二狗!一起坚持!一起学习!
每日一课,无论长短,有所学有所得
业精于勤技在专,行则将至事必成
此前关于测试写过一篇内容一文搞定golang单元测试;
今天这篇内容是对测试内容的补充,目录如下:
表格驱动测试
表格测试是一种编写更清晰的测试函数的方法;
顾名思义,表格驱动测试,就是指通过表格列举的方式来实现测试用例,表格中包含输入和预期输出,以及其他信息;这种方式是我们对测试的逻辑和思路更加清晰;
官方表格驱动测试的案例:
// fmt包中有如下一段测试代码:
// 定义测试的表格,包含了in输入字段和out期待输出字段
// 并且定义了该表格中的测试用例
// 然后使用t.Run的方式对每个用例进行测试
var flagtests = []struct {
in string
out string
}{
{"%a", "[%a]"},
{"%-a", "[%-a]"},
{"%+a", "[%+a]"},
{"%#a", "[%#a]"},
{"% a", "[% a]"},
{"%0a", "[%0a]"},
{"%1.2a", "[%1.2a]"},
{"%-1.2a", "[%-1.2a]"},
{"%+1.2a", "[%+1.2a]"},
{"%-+1.2a", "[%+-1.2a]"},
{"%-+1.2abc", "[%+-1.2a]bc"},
{"%-1.2abc", "[%-1.2a]bc"},
}
func TestFlagParser(t *testing.T) {
var flagprinter flagPrinter
for _, tt := range flagtests {
t.Run(tt.in, func(t *testing.T) {
s := Sprintf(tt.in, &flagprinter)
if s != tt.out {
t.Errorf("got %q, want %q", s, tt.out)
}
})
}
}
如果测试用例我们例举了非常多的话,我们希望测试用例可以并行执行,本身每个测试用例之间就是互不干扰的,因此上述代码可如下优化:
func TestFlagParser(t *testing.T) {
var flagprinter flagPrinter
for _, tt := range flagtests {
ft := tt // 1. 重新声明变量,避免多个goroutine中使用了相同的变量
t.Run(ft.in, func(t *testing.T) {
t.Parallel() // 2. 使用t.Parallel表示每个子测试之间能够彼此并行运行
s := Sprintf(ft.in, &flagprinter)
if s != ft.out {
t.Errorf("got %q, want %q", s, ft.out)
}
})
}
}
如上,既是表格驱动测试
的用法;先定义表格以及测试用例,然后再通过t.Run
子测试方式遍历表格;
自动生成表格驱动测试的代码gotests
gotests
是一种自动生成表格驱动测试代码的工具;
使用案例:
比如在此前的一文搞定golang单元测试中,我们创建了
split.go
的业务文件;安装
gotests
工具:$ go get -u github.com/cweill/gotests/...
-
执行命令:
gotests -all -w split.go
;关于gotests
的命令参数,大家可以去官网学习一下;-
-all
:生成所有的测试函数和方法 -
-w
:输出测试结果到文件而不是控制台
-
-
生成的测试代码的格式如下,我们需要在todo的位置添加我们的测试逻辑即可:
package base_demo import ( "reflect" "testing" ) func TestSplit(t *testing.T) { type args struct { s string sep string } tests := []struct { name string args args wantResult []string }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if gotResult := Split(tt.args.s, tt.args.sep); !reflect.DeepEqual(gotResult, tt.wantResult) { t.Errorf("Split() = %v, want %v", gotResult, tt.wantResult) } }) } }
go测试工具包--testfy
安装go get github.com/stretchr/testify
;提供了更优雅的,灵活的,可mock的等等工具;
常用:testify/assert
或testify/require
或testfy/mock
示例:
单元测试的时候,经常需要用到断言来检验测试结果,但是golang官方没有提供断言语法,导致我们可能会使用大量的ifelse语句;
testfy/assert
为我们提供了很多常用的断言函数,让我们的测试代码实现的更加优雅;
比如在此前的一文搞定golang单元测试中我们检验TestSplit
结果的方式如下:
if !reflect.DeepEqual(want, got) {
t.Errorf("expected:%v, got:%v", want, got)
}
如果我们使用testfy/assert
的话,就可以如下简化:
// t是testing.T
assert.Equal(t, want, got) // 使用assert提供的断言函数;
//或者如下使用方式,先创建assert对象:
assert := assert.New(t)
assert.Equal(123, 123, "they should be equal")//是否相等测试
assert.NotEqual(123, 456, "they should not be equal")//是否不等测试
assert.Nil(object)//是否nil测试
if assert.NotNil(object) {
assert.Equal("Something", object.Value)
}
testfy
中除了assert工具以外,还有常用的是testfy/require
工具,以及还提供了mock
和http
的工具,大家可以去官网了解一下;
什么是mock呢?比如我们的测试中有一个步骤是向用户成功发送邮件,事实上我们需要用户确认邮件后,才认为该邮件用户已确认;但实际测试中,我们不可能真的给用户发送邮件,或者说我们不可能每次测试都真的发送邮件(假如不是邮件而是短信的话,每次测试可都是需要花钱的),因此mock就可以模拟用户确认短信的行为,即模拟功能;
mock技术可用于各种不同的系统,例如模拟数据库查询或者是与其他API的交互等等,非常实用;
关注李二狗 持续精进
坚持每日输出go开发+面试题+算法+工作经验等后端相关技术
关于我今年的计划请查看flag-2022
更多博客内容请查看bigshake
微信公众号李二狗的星球