• Golang 单元测试合集整理,(我最常用 gomonkey)欢迎收藏


    无论写什么样的语言,单元测试都是必不可少的,它可以极大的提高我们的代码质量,减少各种低级错误和 bug

    无论你是一个靠谱合格的码农,还是一个优秀的程序员单元测试都是咱们必须落实的一环

    单元测试比较容易,此处梳理了了基本的单元测试用到的方式和第三方库的使用方式,用到的时候,可以来这里查询 mock 第三方库的地址和基本用法,欢迎收藏

    基本的单元测试

    • Golang 单元测试文件名

    xxx_test.go

    • 单元测试函数

    func Testxxx (t * testing.T){}

    • 子测试 的写法

    t.Run("case1", func(t * testing.T){})

    • 使用工具生成单测文件和函数

    Goland 的方式

    1. 选中我们的 go 源码文件
    1. 右击函数名,可以按照函数来生成单元测试函数,也可以将整个源码都各自生成单元测试函数,生成的函数都会放到 xxx_test.go 文件中

    使用 gotests 工具

    也可以在 Linux 中使用 gotests 工具来生成单测文件和单测函数,生成的效果和 Gland 的方式一致,基本的使用方式如下:

    linuxgo get 一下 gotests 第三方工具

    go get -u github.com/cweill/gotests/...
    
    • 1

    我们可以在咱们的 GOPATH 下的 bin 目录下看到已经有 gotests 这个可执行程序

    使用 gotests 也是非常简单,直接执行如下命令即可生成源码文件对应的单测文件,如需要更加详细的指令,可以查看 gotests --help

    • gotests -all -w xxx.go

    上述 2 个工具,生成的单测文件,单测函数,全部都是符合 goland 的单测要求

    • 基本的单测命令

    • go test

    可以直接看到执行结果是通过,还是失败

    • go test -v

    可以查看到每一个单测函数的执行情况

    • go test -run=xx

    run=[支持正则的字符串] , go test 会去匹配 run 后面的字符串,支持正则,会去匹配到具体的单测函数,并进行测试

    • go test -short

    在单测函数中,执行如下代码,并在命令行运行单测的时候,可以跳过指定的单测函数

          func TestSkipFunc(t *testing.T) {
             if testing.Short() {
                 t.Skipf("跳过当前这个用例")
             }
             。。。
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用 golang 的 并发 测试

    我们知道,我们写单测的时候可以使用 golang 的子测试,例如咱们测试获取用户信息的接口的时候,就可以这样:

    func Test_getUserInfo(t *testing.T) {
       type args struct {
          uid string
       }
       tests := []struct {
          name    string
          args    args
          want    string
          wantErr bool
       }{
          // TODO: Add test cases.
    {
             "case1",
             args{
                "111",
             },
             "hello111",
             false,
          },
       }
       for _, tt := range tests {
          t.Run(tt.name, func(t *testing.T) {
             got, err := getUserInfo(tt.args.uid)
             if (err != nil) != tt.wantErr {
                t.Errorf("getUserInfo() error = %v, wantErr %v", err, tt.wantErr)
                return
             }
             if got != tt.want {
                t.Errorf("getUserInfo() got = %v, want %v", got, tt.want)
             }
          })
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在 golang 的子测试中,即在 t.Run(xxx,xxx) 中进行使用即可并发测试我们的用例,我们可以加入这个语句: t.Parallel()

    xxx
    
    t.Run("xxxx", func(t *testing.T) {
       t.Parallel()
       xxxxxx
    })
    
    xxx
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试覆盖率

    • 查看覆盖率

      • go test -cover

    例如这样

    • 生成覆盖率文件

    将覆盖率的数据生成覆盖率文件,例如 res.out,再使用 go tool 工具转换成 html 源码,咱们直接就可以在浏览器中查看

    • go test -cover -coverprofile=res.out

    • go tool cover -html=res.out

    将生成的 html 文件,可以使用浏览器打开,即可以看到具体的单测结果

    使用断言工具 testify

    go get github.com/stretchr/testify
    
    • 1

    我们可以在测试函数中加上关于断言的语句就很 nice 了,无需自己去写反射对应的值,然后再进行判断

    使用 assert 包,我们直接执行 assert 对应的函数即可完成断言,根据不同的断言需求,有不同的函数例如

    例如我们使用 Equal 函数,就可以这样使用

    import "github.com/stretchr/testify/assert"
    
    func Testxxx(t * testing.T){ 
        myAssert := assert.New(t)
        myAssert.Equal("期望的值", "实际的值", "如果期望的和实际的相等就ok,不符合就报错误信息")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    关于 golang testify assert 可以查看官网:assert package - github.com/stretchr/testify/assert - Go Packages ,这里有更详细的用法,本文是为了帮助查询和索引

    httptest 网络测试工具

    httptest 这个工具,见名知意,是一个测试网络接口的工具,使用它,我们就可以在不启动具体 web 服务的情况下去测试 web 接口

    httptest 是标准库 net 包中的模块,代码中这样导入:

    import "net/http/httptest"
    
    • 1

    基本的使用方式和案例可以查看:https://pkg.go.dev/net/http/httptest#example-Server,有需求的可以自取

    gock golang 网络测试 mock 工具

    go get -u gopkg.in/h2non/gock.v1
    
    • 1

    代码中

    import "gopkg.in/h2non/gock.v1"
    
    • 1

    具体案例可以查看如下地址,这里就不写其他例子了:

    https://pkg.go.dev/gopkg.in/h2non/gock.v1#readme-examples

    go-sqlmock mock mysql 工具

    看到工具名称,我们就可以知道,这个是来 mock 数据库的,当我们没有环境或者数据库没有办法正常使用的时候,我们就可以使用 go-sqlmock 工具,用起来非常方便

    go get github.com/DATA-DOG/go-sqlmock
    
    • 1

    代码中

    import  "github.com/DATA-DOG/go-sqlmock"
    
    • 1

    案例地址:https://github.com/DATA-DOG/go-sqlmock

    miniredis mock redis 的工具

    同理,这是一个 redis 的 mock 工具,我们可以查看地址,来进行查看案例:

    https://github.com/alicebob/miniredis

    go get github.com/alicebob/miniredis/v2
    
    • 1

    代码中

    import "github.com/alicebob/miniredis/v2"
    
    • 1

    Mock 接口工具 gomock

    Gomock 用起来还是非常不错的,可以 一样可以 mock 数据库,还会给我们生成相应的 mock 实现代码,我们在单测文件中,直接使用即可,用起来还是非常傻瓜的

    首先需要确保我们的$GOPATH/bin已经加入到环境变量中。

    我们可以这样来安装这个第三方库

    go get github.com/golang/mock/gomock
    go install github.com/golang/mock/mockgen@v1.6.0
    
    • 1
    • 2

    同样,安装后,在我们的 $GOPATH/bin 下面可以看到有 mockgen 工具

    生成 mock 代码:

    mockgen -source=具体的数据库源码文件 -destination=生成的具体文件 -package=包名
    
    • 1

    使用方式:

    例如

    • 代码中编写具体业务代码

    可以看到下图中,我们的 DB 有两个接口,一个是 Get 一个是 Add

    • 执行命令,生成 mock 代码

    mockgen -source=server.go -destination=./db_mock.go -package=server

    执行之后,我们就可以看到,我们的同级目录下生成了 db_mock.go 文件,里面是关于 mock 的实现,这里面实现了具体的数据库对应的接口

    • 对于我们需要写单测的函数来一键生成单测代码,并调用刚才生成的 db_mock.go代码的实现

    更多关于 gomock 的使用方式和案例,可以查看地址:

    https://github.com/golang/mock

    go stub 打桩,可以支持对全局变量的打桩

    首先对于打桩,我们真的知道他具体表示的含义是什么吗?此处简单说明一下:

    在软件测试中,打桩是指用一些代码(桩stub)代替目标代码,通常用来屏蔽或补齐业务逻辑中的关键代码方便进行单元测试。

    简单来说,就是为了处理了方便,去替换原有的代码实现

    例如一些方法未实现,或者一些资源例如数据库环境不允许,这个时候就可以使用打桩了

    go get github.com/prashantv/gostub
    
    • 1

    代码中

    import "github.com/prashantv/gostub"
    
    • 1

    关于 go stub 的案例,我们可以查看地址:https://github.com/prashantv/gostub

    对于 go stub 我用的比较少,一般会玩一下他的打桩全局变量,因为我一般都是使用 gomonkey 来写单元测试,真的是 yyds

    Go monkey 非常强大的打桩工具(我最常用)

    • 他可以对于普通函数 mock
    • 他可以对于对象方法 mock

    github:https://github.com/bouk/monkey

    就上述这两种,就已经涵盖了我们几乎所有的单元测试

    下载库

    go get bou.ke/monkey
    
    • 1

    代码中

    import "bou.ke/monkey"
    
    • 1

    使用方式

    • Mock 普通函数使用 monkey.Patch ,例如
    monkey.Patch(getSpName,func ( uid string) (string, error) {
       if uid == "111"{
          return "hello111",nil
       }
       return "you are failed",fmt.Errorf("your uid is error")
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • Mock 成员方法 使用 monkey.PatchInstanceMethod,例如
    monkey.PatchInstanceMethod(reflect.TypeOf(u),"GetUserAge",func(*User)int{
          return 100
    })
    
    • 1
    • 2
    • 3

    由于 golang 会进行内联优化,且 go mokey 不是并发安全的,因此我们需要注意以下两点:

    • 执行 go test 的时候使用 go test -v -gcflags=-l
    • 写单元测试的使用,不用使用并发测试

    当然具体的详细案例,可以查看地址:https://github.com/bouk/monkey

    这个工具用起来再接下下面的 go convey 真的非常 nice

    Go Convey 更好的单测框架

    • 集成了 go test,有丰富的断言框架,还有彩色用例结果

    Github 地址

    https://github.com/smartystreets/goconvey
    
    • 1

    安装

    go get github.com/smartystreets/goconvey
    
    • 1

    代码中

    import c "github.com/smartystreets/goconvey/convey"
    
    • 1

    使用

    • 一个 Convey 一个测试用例
    • 嵌套测试,使用多个 Convey
    // 单个 convey
     c.Convey("testcase", func() {
             res := checkPalindrome(tt.in)
             c.So(res, c.ShouldResemble, res)
          })
    
    
    
    
    // 多个 convey 嵌套
    c.Convey("表格驱动", t, func() {
       //myAssert := assert.New(t)
       tests := []struct {
          in  string
          res bool
       }{
          {
             "aaa",
             true,
          },
          {
             "aba",
             true,
          }
       }
    
       for index, tt := range tests {
          c.Convey(fmt.Sprintf("Pal%d", index), func() {
             //t.Parallel()
             res := checkPalindrome(tt.in)
             c.So(res, c.ShouldResemble, res)
          })
       }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    这里我们可以看到使用 Convey ,他包含了 test,又高于 test

    Go convey 还不仅仅这一点,他还有可视化的 ui 界面,我们可以在终端开启 goconvey 的服务,如:

    • goconvey -port 9999
    • 然后打开本地的 http://localhost:9999/ 即可看到具体的单测结果,每一个案例都可以看到是成功还是失败,以及失败的原因

    当然,关于 go convey 的具体使用细节和进阶,可以查看地址:https://github.com/smartystreets/goconvey ,用起来这个 feel 倍儿爽

    感谢阅读,欢迎交流,点个赞,关注一波 再走吧

    欢迎点赞,关注,收藏

    朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

    好了,本次就到这里

    技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

    我是阿兵云原生,欢迎点赞关注收藏,下次见~
    可以进入地址进行体验和学习:https://xxetb.xet.tech/s/3lucCI

  • 相关阅读:
    VScdoe将字体修改为宋体
    HTML+CSS+JS学习
    VueUI Day01(7.29)Vue 组件库、Vue 组件库、NavMenu 组件、ElementUI 的布局相关组件
    gprof 分析程序执行时间和函数调用次数
    资深测试面试-参考一下
    HTML+CSS鲜花网页制作 DW静态网页设计 简单的个人网页制作
    RabbitMq
    如何解决跨区域文件传输存在的安全管控问题?
    【论文复现】基于多模态深度学习方法的单细胞多组学数据聚类(【生物信息学】实验二:多组学数据融合:scMDC)
    Web前端大作业——基于HTML+CSS+JavaScript仿英雄联盟LOL游戏网站
  • 原文地址:https://blog.csdn.net/m0_37322399/article/details/132864821