Golang 单元测试和基准测试实例详解
作者:六号积极分子 发布时间:2024-05-05 09:27:58
前言
多人协作的项目里,要保证代码的质量,自然离不开单元测试。开发完一个功能后肯定要对所写的代码进行测试,测试没有问题之后再合并到代码库供他人使用。如果强行合并到代码库可能会影响其他人开发,被上线的话肯定也会导致线上 Bug ,影响用户使用。
所以,单元测试也是一个很重要的事情。单元测试是指在开发中,对一个函数或模块的测试。其强调的是对单元进行测试。
Go 单元测试
Go 语言提供了单元测试的框架,只要遵循其规则即可:
测试文件命名:
单元测试的代码文件都必须以 _test.go 结尾,这样才能被 Go 语言测试工具识别
单元测试的文件命名都与被测试函数所在的 go 文件的文件名一样,然后再加 _test.go。比如 main.go 的测试文件 main_test.go
测试函数命名:
单元测试的函数名必须以 Test 开头,再加上要测试函数名,且必须是公有的。比如main.go中有函数
func add(){}
, 其函数名应为TestAdd
测试函数的签名必须接收一个指向 testing.T 类型的指针,并且不能返回任何值
# main.go
func Add(){
// to do something
}
# main_test.go
func TestAdd(t *testing.T) {
result := Add()
if result == 3 {
println("success")
} else {
println("error")
}
}
根据以上规则,就可以进行对某测试文件执行命令,进行单元测试:
go test -v ./main_test.go
如果显示的测试结果有 PASS 标记,说明单元测试通过。
单元测试覆盖率
函数是否被全面测试,还需要覆盖率进行检测。单元测试命令增加 --coverprofile 标记,就可以得到一个单元测试覆盖文件,且会在控制台打印出代码覆盖率是多少。
go test -v --coverprofile=main.cover ./main_test.go
Go 框架还可以生成 html 文件的覆盖率报告,这样就可以对单元测试覆盖率的结果更清晰,更明白。
go tool cover -html=main.cover -o=main.html
打开 html 文件就可以看到红色标记是没有被覆盖到,绿色是被测试到的。
以上是简单的功能的单元测试,验证功能逻辑的正确。但有时候还有性能的要求,这时就可以使用基准测试来评估代码的性能。
基准测试
基准测试是一项用于测试和评估软件性能指标的方法,主要测试代码的性能。基准测试的规则和单元测试的规则是不一样的:
基准测试函数必须以 Benchmark 开头,且必须是可导出的
函数的签名必须接收一个指向 testing.B 类型的指针,并且不能返回任何值;
最后的 for 循环很重要,被测试的代码要放到循环里;
b.N 是基准测试框架提供的,表示循环的次数,因为需要反复调用测试的代码,才可以评估性能。
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add()
}
}
写完基准测试,就可以执行命令进行测试:
go test -bench=. ./
使用 go test 命令,再加上 -bench 这个 Flag,它接受一个表达式作为参数,以匹配基准测试的函数,"."表示运行所有基准测试。
BenchmarkAdd-10, 其中的 -10 是运行基准测试时对应的 GOMAXPROCS 的值。基准测试的时间默认是 1 秒,也就是 1 秒调用 1000000000 次、每次调用花费 311 纳秒。如果想让测试运行的时间更长,可以通过 -benchtime 指定,比如 3 秒。
go test -bench=. -benchtime=3s ./
重置计时方法
进行基准测试之前,需要进行一些数据准备,如构建测试数据,而这部分准备工作不属于性能测试计算范围内所以需要排除在外。通过使用充值计数器 ResetTimer重新计算。也支持使用 StartTimer 和 StopTimer 方法,控制何时开始计时何时结束。
内存统计
内存统计主要是统计每次操作分配内存的次数和分配的字节数。使用 ReportAllocs() 方法
func BenchmarkAdd(b *testing.B) {
b.ResetTimer() // 重置计时时间
b.ReportAllocs() // 内存统计
for i := 0; i < b.N; i++ {
Add()
}
}
对以上命令执行后可在控制台上得到结果。多了两个指标。
第一个表示:每次操作分配多少字节内存
第二个表示:每次操作分配内存的次数
两个指标没有统一标准区说明越小越好还是越大越好,主要还是需要根据业务场景来判断的。
并发基准测试
在并发的情况下,Go 也支持基准测试。Go 语言通过 RunParallel 方法运行并发基准测试。创建多个 goroutine 然后将 b.N 分配给这些 goroutine 执行。
func BenchmarkAdd(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Add()
}
})
}
单元测试可以保证代码质量,但其也不是万能的,还需要 code Review 和人工测试才能更好的保证代码的质量。
参考资料:https://www.aspxhome.com/article/260482.htm
来源:https://juejin.cn/post/7134990561693401119


猜你喜欢
- 1. document.form.item 问题 (1)现有问题:现有代码中存在许多 document.formName.item(&quo
- 前言在之前的一篇文章Python可视化神器-Plotly动画展示展现了可视化神器-Plotly的动画的基本应用,本文介绍如何在Python中
- 我要坦白一点。尽管我是一个应用相当广泛的公共域 Python 库的创造者,但在我的模块中引入的单元测试是非常不系统的。实际上,那些测试大部分
- python中,count函数的作用是进行python中的数量计算。count函数用于统计字符串、列表或元祖中某个字符出现的次数,是一个很好
- 用户认证组件:功能:用session记录登录验证状态前提:用户表:django自带的auth-userpython3 manage.py c
- 一、Position1、语法:position:static/ absolute / fixed / relative2、参数:(1)sta
- 一 引入我们学习变量是为了让计算机能够像人一样去记忆事物的某种状态,而变量的值就是用来存储事物状态的,很明显事物的状态分成不同种类的(比如人
- 本文实例讲述了mysql聚簇索引的页分裂。分享给大家供大家参考,具体如下:在MySQL中,MyISAM采用的是非聚簇索引的,InnoDB存储
- 增大 SGA 已经缓冲看来对于性能的提升并不显著,加载时间只提升了 1.73%。下面我们增加 SGA 重做日志的大小: DB3: Log B
- 前两天我在工作中遇到这样一个问题,我们有一个程序是用来增量抽取EBS 中的表数据的,有的是全量抽取,即先删除原表中的数据,然后重新抽取数据,
- 1、不指定开始和结束的索引[:],这样得到的切片就可以包含整个列表,然后给切片一个新的变量,从而实现复制列表。2、创建原始列表的副本,两个列
- Celery 简介除了redis,还可以使用另外一个神器---Celery。Celery是一个异步任务的调度工具。Celery 是 Dist
- PyQt的使用与pycharm的结合环境安装pip install pyqt5 -i https://pypi.tuna.tsinghua.
- 引言阿刁是一个自动化测试用例,从一出生他就被赋予终生使命,去测试一个叫登录的过程是否合理。他一直就被关在一个小黑屋里面,从来也没有出去过,小
- # 配置vuex和在vue中相同,只是mpvue有一个坑,就是不能直接在new Vue的时候传入store。步骤:1.在src目录下新建一个
- Web 标准要求一览表Russ WeakleyJjgod Jiang14-Aug-2004目录1 Web 标准,不仅仅是“不用表格的站点”2
- 很多小伙伴都会有这样的问题,说一个ip地址十分钟内之内注册一次,用来防止用户来重复注册带来不必要的麻烦逻辑:取ip,在数据库找ip是否存在,
- paramiko模块提供了ssh及sft进行远程登录服务器执行命令和上传下载文件的功能。这是一个第三方的软件包,使用之前需要安装。1 基于用
- 在使用django-rest-framework开发项目的时候我们总是避免不了跨域的问题,因为现在大多数的项目都是前后端分离,前后端项目部署
- 写爬虫有一个绕不过去的问题就是验证码,现在验证码分类大概有4种:图像类滑动类点击类语音类今天先来看看图像类,这类验证码大多是数字、字母的组合