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 golang.guazi-corp.com/finance/lego/model/imports/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

  1. 执行下面命令
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=接口名