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

news2025/1/21 2:56:39

无论写什么样的语言,单元测试都是必不可少的,它可以极大的提高我们的代码质量,减少各种低级错误和 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/...

我们可以在咱们的 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("跳过当前这个用例")
         }
         。。。
      }

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

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

xxx

t.Run("xxxx", func(t *testing.T) {
   t.Parallel()
   xxxxxx
})

xxx

测试覆盖率

  • 查看覆盖率

    • 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

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

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

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

import "github.com/stretchr/testify/assert"

func Testxxx(t * testing.T){ 
    myAssert := assert.New(t)
    myAssert.Equal("期望的值", "实际的值", "如果期望的和实际的相等就ok,不符合就报错误信息")
}

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

httptest 网络测试工具

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

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

import "net/http/httptest"

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

gock golang 网络测试 mock 工具

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

代码中

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

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

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

代码中

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

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

miniredis mock redis 的工具

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

https://github.com/alicebob/miniredis

go get github.com/alicebob/miniredis/v2

代码中

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

Mock 接口工具 gomock

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

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

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

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

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

生成 mock 代码:

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

使用方式:

例如

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

可以看到下图中,我们的 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

代码中

import "github.com/prashantv/gostub"

关于 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

代码中

import "bou.ke/monkey"

使用方式

  • 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")
})
  • Mock 成员方法 使用 monkey.PatchInstanceMethod,例如
monkey.PatchInstanceMethod(reflect.TypeOf(u),"GetUserAge",func(*User)int{
      return 100
})

由于 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

安装

go get github.com/smartystreets/goconvey

代码中

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

使用

  • 一个 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)
      })
   }
})

这里我们可以看到使用 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1007388.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python:使用RESTful API(flask)调用python程序传递参数,实现Web端调用python程序

问题描述 现有一个用python写的程序(或者是一个或几个的函数接口),需要在Web前端调用python写的函数。如果直接用前端java来调用会很不方便,而且会出现各种麻烦的问题,下面给出如何在web前端调用python的接口。 解决…

STM32WB55开发(2)----修改蓝牙地址

STM32WB55开发----2.修改蓝牙地址 概述硬件准备视频教学样品申请完整代码下载选择芯片型号配置时钟源配置时钟树RTC时钟配置查看开启STM32_WPAN条件配置HSEM配置IPCC配置RTC启动RF开启蓝牙设置工程信息工程文件设置修改置BLE设备公共地址Ble_Hci_Gap_Gatt_Init结果演示 概述 在…

更多场景、更多选择,Milvus 新消息队列 NATS 了解一下

在 Milvus 的云原生架构中,消息队列(Log Broker)可谓任重道远,它不仅要具备流式数据持久性、支持 TT 同步、事件通知等能力,还要确保工作节点从系统崩溃中恢复时增量数据的完整性。 在 Milvus 的架构中,一切…

【计算机视觉 | 语义分割】干货:语义分割常见算法介绍合集(一)

文章目录 一、U-Net二、Fully Convolutional Network三、SegNet四、DeepLab五、DeepLabv3六、UNet七、PSPNet八、EfficientDet九、SegFormer十、ENet 一、U-Net U-Net 是一种语义分割架构。 它由收缩路径和扩张路径组成。 收缩路径遵循卷积网络的典型架构。 它由两个 3x3 卷积…

基于SSM的学生信息管理系统设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

Python 图形化界面基础篇:使用包装器( Pack )布局元素

Python 图形化界面基础篇:使用包装器( Pack )布局元素 引言什么是 Tkinter 的 Pack 布局?步骤1:导入 Tkinter 模块步骤2:创建 Tkinter 窗口步骤3:创建和使用 Pack 布局步骤4: Pack 布…

Android codec2 编码 -- 基于录屏

文章目录 前言android 原生的应用srcreenrecordMediaCodec获取编码数据流程 前言 本篇文章主要是理解Android 12编码的流程, 首先从上层的应用出发理解mediacodec提供给外部API的用法。然后针对每个api 分析编码各个流程中框架中的流程。 熟悉一个框架的流程 可以…

嵌入式这个领域会变得过于内卷吗?

今日话题,嵌入式这个领域会变得过于内卷吗?嵌入式开发主要服务于第二产业,尤其是制造业,包括电器、电气、机械、汽车、装备、航空航天等行业的“智能制造”部门,稳定性较强,不像互联网行业那样波动大。因此…

【LangChain系列 8】Prompt模版——少样本prompt模版(二)

原文地址:【LangChain系列 8】Prompt模版——少样本prompt模版(二) 本文速读: 固定少样本prompt模版 动态少样本prompt模版 在上篇文章中介绍了少样本模版的基本用法,本文将介绍 对话模型(chat model) 中 少样本prompt模版的用法。 LangCh…

C语言双向链表

文章目录 前言双向链表链表头结点的创建节点尾插与尾删节点头插与头删特定位置插入或删除节点链表节点查找双向链表的销毁 链表的打印 前言 假期时间因为为学校开学考试做准备所以一直没更新博客,今天开始博客会陆续更新。 双向链表 之前我们说过了顺序表和单链表…

加密狗软件有什么作用?

加密狗软件是一种用于加密和保护计算机软件和数据的安全设备。它通常是一个硬件设备,可以通过USB接口连接到计算机上。加密狗软件的作用主要体现在以下几个方面: 软件保护:加密狗软件可以对软件进行加密和授权,防止未经授权的用户…

K8S:kubectl陈述式、声明式资源管理及金丝雀部署

文章目录 一.陈述式资源管理方法1.陈述式资源管理概念2.基本信息查看(1)查看版本信息(2)查看资源对象简写(3)查看集群信息(4)配置kubectl自动补全(5)node节点…

【Java实战项目】【超详细过程】—大饼的图片服务器4

目录 1.引入servlet依赖2.处理客户端请求2.1 上传图片2.1.1.获取图片属性写入数据库(1)创建factory对象和fileUpload对象为获取图片信息做准备(2)将获取到的文件信息存到列表items中(3)获取列表items中第一…

无涯教程-JavaScript - XNPV函数

描述 XNPV函数返回的现金Stream量表的净现值不一定是周期性的。要计算一系列定期现金Stream量的净现值,请使用NPV函数。 语法 XNPV (rate, values, dates)争论 Argument描述Required/OptionalRateThe discount rate to apply to the cash flows.RequiredValues 与日期付款时…

(已解决)AttributeError: module ‘cv2.gapi.wip.draw‘ has no attribute ‘Text‘

问题描述 今天再跑Caption-Anything项目的时候,最开始的时候就报了这样一个错误:AttributeError: module cv2.gapi.wip.draw has no attribute Text。 Caption-Anything是一种多功能的图像处理工具,结合了Segment Anything,Visual…

前端项目开发流程

一 参加需求对称(评审)会议 时间:在产品设计完成以后,进入正式的开发流程之前 组织者:产品&项目经理 目的:统一大家对产品的认识,及时发现产品设计缺陷,尽可能降低后续修改需求的频率 参与者&#xff…

短信验证码的登录注册功能

1 基于session实现登录流程 1.1发送验证码: 用户在提交手机号后,会校验手机号是否合法,如果不合法,则要求用户重新输入手机 如果手机号合法,后台此时生成对应的验证码,同时将验证码进行保存,然…

【计算机视觉 | 目标检测】干货:目标检测常见算法介绍合集(二)

文章目录 十六、EfficientDet十七、Deformable DETR十八、YOLOX十九、Sparse R-CNN二十、Contour Proposal Network二十一、VarifocalNet二十二、Libra R-CNN二十三、Stand-Alone Self Attention二十四、ThunderNet二十五、Hierarchical Transferability Calibration Network二…

垃圾收集算法

1.如何判断对象是否存活? 1.1引用计数算法 基本思路: 在对象中添加一个引用计数器每当有一个地方引用它的时候,计数器就加1每当有一个引用失效的时候,计数器就减-1当计数器的值为0的时候,那么该对象就是可被GC回收的…

leetcode 2366. Minimum Replacements to Sort the Array(数组排序的最少替换数)

数组nums中的元素nums[ i ] 可以替换为任意两个数a, b, 前提是ab nums[ i ]. 把数组nums变为升序&#xff08;可以有相等&#xff09;数组需要多少次替换。 思路&#xff1a; 排序数组是左边的元素<右边元素&#xff0c;以右边元素为边界。 所以从右到左遍历数组&#xf…