golang 单元测试

文件格式:go单元测试,有固定的名称格式,所有以_test.go为后缀名的源文件在执行go build 时不会被构建成包的一部分,他们是go test 测试的一部分。

测试函数

函数格式:每个测试函数是以Test为函数名称前缀。

每个测试函数必须导入testing包。

func TestName(t *testing.T) {

// ...

}

基准测试(benchmark)

函数格式:函数前缀名称Benchmark。

作用:用于衡量函数的性能。会多次运行基准函数,计算一个平均的执行时间。

示例函数

函数前缀名称Example

作用:提供一个由编译器保证正确性的示例文档。

命令介绍

go test -v

2.-run 测试制定的函数名称

go test -v -run="函数名称"

3.-cover 查看测试覆盖率

go test -v -run="" -cover

go test -cover /model/test/list

4.最后统统执行一遍全部测试用例

go test

5.示例

go test -run '' # Run all tests.

go test -run Foo # Run top-level tests matching "Foo", such as "TestFooBar".

go test -run Foo/A= # For top-level tests matching "Foo", run subtests matching "A=".

go test -run /A=1 # For all top-level tests, run subtests matching "A=1".

表格驱动测试(自动生成)

安装gotests

执行下面命令

go get -u github.com/cweill/gotests

2.将下载的gotests目录,配置到PATH环境变量中

export PATH=$PATH:$GOBIN:$GOPATH:$MYSQLBIN

gotests使用

-all

generate tests for all functions and methods

为所有函数和方法生成go测试

-excl string

为没有匹配的函数和方法生成go测试

regexp. generate tests for functions and methods that don't match. Takes precedence over -only, -exported, and -all

-exported

为导出的函数和方法生成go测试。

generate tests for exported functions and methods. Takes precedence over -only and -all

-i

在错误消息中打印测试输入

print test inputs in error messages

-nosubtests

禁用子测试生成。仅适用于Go 1.7

disable generating tests using the Go 1.7 subtests feature

-only string

正则表达式。生成仅匹配的函数和方法的测试。优先于-all

regexp. generate tests for functions and methods that match only. Takes precedence over -all

-template_dir string

可选的。包含自定义测试代码模板的目录的路径

optional. Path to a directory containing custom test code templates

-w

将输出写入(测试)文件而不是stdout

write output to (test) files instead of stdout

常用操作

1.进入对应的要被生成单元测试的目录

2.在该目录下执行命令

3.生成指定函数的单元测试,输出到命令行,然后复制粘贴到目标处。

gotests -only "函数名称" 文件名称.go

4.生成全部测试函数

gotests -all 文件名称.go

gotests -only " 方法名称" 文件名称

gotests -all -w origin.go, origin_test.go

会自动创建在当前目录下,并自动生成测试代码,只需要将不同的测试数据按照tests定义的结构写在//TODO:Add test cases下面,测试用例就完成了。

mock测试

参考文章

mock是单元测试中常用的一种测试手法,mock对象被定义,并能够替换掉真实的对象被测试的函数所调用。

而mock对象可以被开发人员很灵活的指定传入参数,调用次数,返回值和执行动作,来满足测试的各种情景假设。

使用场景

依赖的服务返回不确定的结果,如获取当前时间。

依赖的服务返回状态中有的难以重建或复现,比如模拟网络错误。

依赖的服务搭建环境代价高,速度慢,需要一定的成本,比如数据库,web服务

依赖的服务行为多变。

为了保证测试的轻量以及开发人员对测试数据的掌控,采用mock来斩断被测试代码中的依赖不失为一种好方法。

每种编程语言根据语言特点其所采用的mock实现有所不同。

mockery

安装

go get github.com/vektra/mockery/.../

使用

Run: mockery -name=Stringer生成的mock名称 and the following will be output to mocks/Stringer.go

1、生成mock文件,默认在./mocks目录下

mockery -name=Mocker接口名

2、生成mock输出到控制台

mockery -name=接口名 -print

代码处理:

1.业务接口

1.定义被mock的接口

2.定义类(实现接口)

3.定义个方法New(),返回该类对象

// 1.定义接口

type Driver interface {

Add(*ImportSet) (int64, error)

}

// 2.定义类,实现该接口

type driverImp struct{}

//3.定义方法,创建该类对象

func NewDriver() Driver {

return &driverImp{}

}

2.生成mock方法

mockery -name=接口名 -print

生成要被mock的方法

3.service层调用处

// 用创建对象的方法,获取对象,调用接口方法

NewDriver().QueryImportDetails(req.ImportUuid)

4.单元测试

func TestFunc(t *testing.T) {

//保存原来的对象helper.ListDrv就是newDrv()

oldFd := helper.ListDrv

//最后还原对象

defer func() {

helper.ListDrv = oldFd

}()

type args struct {

ctx context.Context

req

}

tests := []struct {

name string

args args

want *****

wantErr bool

//在表驱动中,写mock方法

mock func()

}{

{

name: "error",

args: args{

ctx: context.Background(),

req: **,

},

wantErr: false,

want: ***

mock: func() {

mfd := &listmock.Driver{}

mfd.On("QueryCount").Return(int64(0), nil)

mfd.On("QueryList", mock.Anything, mock.Anything).Return([]list.ImportList{{UUID: "xxx", Description: "ddddd"}}, nil)

//还原对象

helper.ListDrv = mfd

},

},

},

// 测试用例

for _, tt := range tests {

// 执行mock方法

tt.mock()

t.Run(tt.name, func(t *testing.T) {

里面的单元测试内容不变

}

常用命令

-v是显示出详细的测试结果,

-cover 显示出执行的测试用例的测试覆盖率

1 测试单个文件,一定要带上被测试的原文件

go test -v -cover file1_test.go file.go

2 测试单个函数方法

go test -v -cover -run TestFuncName

3 测试整个api包

在包统计目录下

go test -v -cover ./api/...

4、自动生成测试用例,为指定的函数生成单元测试,输出到控制台

gotests -only "函数名称" file(源文件名称).go

5、自动生成测试用例,为指定文件生成单元测试,输出到文件中

gotests -all -w origin.go, origin_test.go

6、生成mock

//输出到控制台

mockery -name=接口名 -print

//输出到./mocks/接口名.go文件中

mockery -name=接口名