Go语言单元测试超详细解析
知识点掌握了,还需要不断练习才能熟练运用。下面golang学习网给大家带来一个Golang开发实战,手把手教大家学习《Go语言单元测试超详细解析》,在实现功能的过程中也带大家重新温习相关知识点,温故而知新,回头看看说不定又有不一样的感悟!
前言:
平时根据需求写代码.人工进行测试往往不会面面俱到,还会因为需求的改变繁琐的进行测试
通过完成一个测试函数,可以大大简化测试的步骤,并且在需求该变的时候只需要改变一下测试的输入与期望
一、单元测试分类及其概念
1.基本分类
- 测试函数 函数前缀为Test 主要用于测试程序的一些逻辑行为是否正确
- 基准函数 函数名前缀为
Benchmark
主要测试函数的性能 - 示例函数 函数的前缀名为
Example
为文档提示示例文档
2.细说单元测试分类
①测试函数
- 函数的基本测试
- 函数的组测试
- 函数的子测试
- 测试函数覆盖率(也就是被测试函数有多少代码用于了执行)
- 在进行测试的时候,要保证被测函数覆盖率为100%,测试函数覆盖率为60%以上,否则写的代码大部分用不到,需要优化
- ①测试覆盖率可以使用
go test -cover
- ②
go test -cover -coverprofile=c.out
(将测试的结果存入文件c.out) - 然后使用
go tool cover -html=c.out
可以打开文件,显示哪些代码没有执行
- ①测试覆盖率可以使用
②基准测试
- 基准函数测试是做什么的:基准函数会自定义一个时间段用于执行代码,如果代码简洁,被测函数的执行次数需要成倍增加(直到达到基准测试函数给的预期,然后统计一共执行了多少轮,,每轮平均用时多少)
- 执行基准函数时,首先要写基准函数
- 基准测试函数的参数是:*testing.B对应的指针变量
- 在测试函数内部要进行循环,循环的终止条件是b.N
二、结合代码细说每一种测试
1.基准测试
(1)基准测试函数需要注意的点
进行基准测试时往往是对函数的算法进行测验,有时后一个算法在测试数据的基量不同时测试出的效果会不同我们需要对不同数量级的样本进行测试的时候。可以自己写一个盒子作为跳板,测试什么数量级的数据就只进行当前数量级的测试
测试的时候命令为:go test -bench=.(将所有的跳板函数均执行一遍)或者=特定函数进行特定函数测试-benchtime=time (在被测试函数在基准函数默认的时间内执行不完时可以拿这个参数进行时间的扩充)在进行基准函数测试的时候,可能需要进行一些前置工作,如果感觉前置工作浪费时间可以使用 b.ResetTimer()对计时器进行重置
(2)基准测试代码
测试函数代码如下:
//文件名 subStr_test.go package main import ( "reflect" "testing" ) func BenchmarkSubStr(b *testing.B) { for i := 0; i <p><strong>被测函数代码如下:</strong></p> <pre class="brush:bash;">//文件名 subStr.go package main import ( "fmt" "strings" ) func subStr(str, stre string) []string { index := strings.Index(str, stre) var theSub []string for index >= 0 { // 先将分隔符前面的数据进行保存 temp := str[:index] // 将字符串往后移 str = str[index+1:] // 重新获取下标 index = strings.Index(str, stre) if temp != "" { theSub = append(theSub, temp) } else { continue } } theSub = append(theSub, str) return theSub[:] } // 菲薄那契数列 func Fib(n int) int { if n <p>将以上两个文件放在同一目录下,执行测试命令 <code>go test</code><br> </p> <p><strong>得到测试结果:</strong></p> <blockquote><p> goos: windows<br> goarch: amd64<br> cpu: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz<br> BenchmarkSubStr-8 1213681 1012 ns/op 352 B/op 14 allocs/op<br> PASS<br> ok _/d_/Go语言学习笔记/go语言语法部分/go语言进阶语法/8.单元测试/基准测试 2.410s</p></blockquote> <h3>2.组测试与子测试</h3>
- 对于一个函数的测试,不仅仅是一组测试用例,所以我们需要写测试组, 对一个函数进行测试,测试的时候一般用集合键值对构成,每一个键对应一组测试数据
- 进行组测试的时候可能会有个别的组出错,所以使用子测试可以对某个案例进行单独测试这就是测试组与子测试的产生背景
测试函数如下:
package main import ( "reflect" "testing" ) type testS struct { str string ste string want []string } //进行组测试,批量进行测试,如果有哪个地方不满足则进行异常抛出 // func TestSubStr(t *testing.T) { // testMap := map[string]testS{ // "case_1": {"123:eqwe:123", ":", []string{"123", "eqwe", "123"}}, // "case_2": {"13:eqwe3:1@23", "3:", []string{"1", "eqwe", "1@23"}}, // "case_3": {"12@3@:@eq@we@:1@23", "@:", []string{"12@3", "@eq@we", "1@23"}}, // "case_4": {"123:eq@we:1@2@3", "q@", []string{"123:e", "we:1@2@3"}}, // "case_5": {"123:eqwe:123", "2", []string{"1", "3:eqwe:1", "3"}}, // "case_6": {"123:eqwe:123", "eqwe", []string{"123:", ":123"}}, // } // for k, v := range testMap { // res := subStr(v.str, v.ste) // if !reflect.DeepEqual(res, v.want) { // t.Errorf("%v want:%#v got:%#v", k, v.want, res) // } // } // } // 进行子测试,可以针对某个子样本进行测试 func TestSubStr(t *testing.T) { testMap := map[string]testS{ "case_1": {"13:eqwe:123", ":", []string{"123", "eqwe", "123"}}, "case_2": {"3:eqwe3:1@23", "3:", []string{"1", "eqwe", "1@23"}}, "case_3": {"2@3@:@eq@we@:1@23", "@:", []string{"12@3", "@eq@we", "1@23"}}, "case_4": {"123:eq@we:1@2@3", "q@", []string{"123:e", "we:1@2@3"}}, "case_5": {"23:eqwe:123", "2", []string{"1", "3:eqwe:1", "3"}}, "case_6": {"123:eqwe:123", "eqwe", []string{"123:", ":123"}}, } for k, v := range testMap { t.Run(k, func(t *testing.T) { res := subStr(v.str, v.ste) if !reflect.DeepEqual(res, v.want) { t.Errorf("want:%#v got:%#v", v.want, res) } }) } }
待测函数如下:
package main import ( "fmt" "strings" ) func subStr(str, stre string) []string { index := strings.Index(str, stre) var theSub []string for index >= 0 { // 先将分隔符前面的数据进行保存 temp := str[:index] // 将字符串往后移 str = str[index+len(stre):] // 重新获取下标 index = strings.Index(str, stre) if temp != "" { theSub = append(theSub, temp) } else { continue } } theSub = append(theSub, str) return theSub[:] } func main() { fmt.Println(subStr("q:w:ec:wer:cd:scn:cj:c:is:icc:cin:si", ":c")) fmt.Printf("%#v\n", subStr("q:w:ec:wer:cd:scn:cj:c:is:icc:cin:si", ":")) fmt.Println(123) }
(1).组测试结果分析及命令:
- 组测试命令仍使用
go test
--- FAIL: TestSubStr (0.00s)
--- FAIL: TestSubStr/case_1 (0.00s)
subStr_test.go:46: want:[]string{"123", "eqwe", "123"} got:[]string{"13", "eqwe", "123"}
--- FAIL: TestSubStr/case_2 (0.00s)
subStr_test.go:46: want:[]string{"1", "eqwe", "1@23"} got:[]string{"eqwe", "1@23"}
--- FAIL: TestSubStr/case_3 (0.00s)
subStr_test.go:46: want:[]string{"12@3", "@eq@we", "1@23"} got:[]string{"2@3", "@eq@we", "1@23"}
--- FAIL: TestSubStr/case_5 (0.00s)
subStr_test.go:46: want:[]string{"1", "3:eqwe:1", "3"} got:[]string{"3:eqwe:1", "3"}
FAIL
exit status 1
FAIL _/D_/Go语言学习笔记/go语言语法部分/go语言进阶语法/8.单元测试/组测试与子测试 0.155s
(2).子测试结果分析及命令:
- 例如单独测试case_1,使用的命令为
go test -v -run=TestSubStr/case_1
(等号后面跟的是上面组测试失败案例FAIL后面的目录)
=== RUN TestSubStr
=== RUN TestSubStr/case_1
subStr_test.go:46: want:[]string{"123", "eqwe", "123"} got:[]string{"13", "eqwe", "123"}
--- FAIL: TestSubStr (0.00s)
--- FAIL: TestSubStr/case_1 (0.00s)
FAIL
exit status 1
FAIL _/D_/Go语言学习笔记/go语言语法部分/go语言进阶语法/8.单元测试/组测试与子测试 0.186s
三、pprof调试工具
1.对主函数进行传参
(1)os.Args package main1 import ( "fmt" "os" ) func main() { // os.Args可以在执行函数的时候传递参数,但是对于-name=xxx没有办法将其解析 if os.Args != nil { for index, temp := range os.Args { fmt.Println("第", index+1, "个参数是:", temp) } } fmt.Println("hello") }
(2)flag.Args
- 相对于os.Args来说,flag.Args使用起来更加方便
package main import ( "flag" "fmt" "time" ) func main() { // 第一个参数为对应的参数,第二个参数为默认值,第三个参数为提示 // 返回的是对应类型的指针 // name := flag.String("name", "Tom", "输入name") // sex := flag.Bool("sex", true, "是不是男性") // age := flag.Int("age", 10, "年龄") // flag.Parse() // fmt.Println(*name, *sex, *age) var name string var age int var sex bool flag.StringVar(&name, "name", "Tom", "输入name") flag.BoolVar(&sex, "sex", true, "是不是男性") flag.IntVar(&age, "age", 10, "年龄") tim := flag.Duration("time", time.Hour, "时间") // 将输入的数据进行解析,不使用这句话的话不能获取到name sex age等属性对应的值 flag.Parse() fmt.Println(name, sex, age, *tim) fmt.Println(flag.Args()) //以切片的方式返回命令行之外的其他参数 fmt.Println(flag.NArg()) //返回命令行之外的其他参数的个数 fmt.Println(flag.NFlag()) //返回使用命令行的参数的个数 }
2.pprof性能调优
pprof
调试工具进行调试,主要看待测模块在内存于时间上的效益调试的时候只会显示耗费时间空间较多的代码段.
生成调试代码块的文件:go run xx.exe -cpu....
使用go语言工具查看代码块所存在的问题:go tool pprof cpu.pprof
package main import ( "flag" "fmt" "os" "runtime/pprof" "time" ) // 一段有问题的代码 func logicCode() { var c chan int for { select { case v := <p><strong>总结:</strong></p> <p>这里对常用的测试函数,子测试进行了详细的讲解,对于pprof参数调优仅仅做了个介绍,可以根据自己的兴趣在网上找一部分pprof的例子深入学习,进行自动化测试非常方便。</p> <p>理论要掌握,实操不能落!以上关于《Go语言单元测试超详细解析》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!</p>

- 上一篇
- Go语言线程安全之互斥锁与读写锁

- 下一篇
- Go语言metrics应用监控指标基本使用说明
-
- 精明的嚓茶
- 感谢大佬分享,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢博主分享技术文章!
- 2023-02-20 12:45:15
-
- 懦弱的帽子
- 这篇博文真是及时雨啊,好细啊,太给力了,已加入收藏夹了,关注大佬了!希望大佬能多写Golang相关的文章。
- 2023-02-13 15:06:44
-
- 健壮的身影
- 太细致了,已收藏,感谢大佬的这篇博文,我会继续支持!
- 2023-01-19 09:03:16
-
- Golang · Go教程 | 17小时前 |
- TigervncDebian多用户共享桌面超简单教程
- 482浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Go语言新手必看!切片vs数组,一次搞定这两个核心知识点
- 472浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Docker在Debian上运行超简单教程(保姆级教学)
- 210浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Debian设置hostname踩坑记录:权限问题大揭秘
- 334浏览 收藏
-
- Golang · Go教程 | 1天前 |
- Debian装SQLServer?这些问题你一定要注意!
- 284浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Debian系统下Jenkins自动化部署脚本教学
- 367浏览 收藏
-
- Golang · Go教程 | 2天前 |
- DebianSwap服务器应用实测,这些场景真的用得上!
- 319浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Debian跑TigerVNC实测!真香警告,快来看看性能咋样~
- 171浏览 收藏
-
- Golang · Go教程 | 2天前 |
- 在Debian上玩转SQLServer备份还原,手把手教你一步步操作
- 498浏览 收藏
-
- Golang · Go教程 | 2天前 |
- DebianOverlay不会玩?手把手教你轻松定制化安装
- 258浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Go语言实战:time.Ticker&time.After用法区别及避坑技巧
- 240浏览 收藏
-
- Golang · Go教程 | 2天前 |
- Debian系统如何快速定位&干掉那些讨厌的僵尸进程
- 317浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 茅茅虫AIGC检测
- 茅茅虫AIGC检测,湖南茅茅虫科技有限公司倾力打造,运用NLP技术精准识别AI生成文本,提供论文、专著等学术文本的AIGC检测服务。支持多种格式,生成可视化报告,保障您的学术诚信和内容质量。
- 18次使用
-
- 赛林匹克平台(Challympics)
- 探索赛林匹克平台Challympics,一个聚焦人工智能、算力算法、量子计算等前沿技术的赛事聚合平台。连接产学研用,助力科技创新与产业升级。
- 50次使用
-
- 笔格AIPPT
- SEO 笔格AIPPT是135编辑器推出的AI智能PPT制作平台,依托DeepSeek大模型,实现智能大纲生成、一键PPT生成、AI文字优化、图像生成等功能。免费试用,提升PPT制作效率,适用于商务演示、教育培训等多种场景。
- 57次使用
-
- 稿定PPT
- 告别PPT制作难题!稿定PPT提供海量模板、AI智能生成、在线协作,助您轻松制作专业演示文稿。职场办公、教育学习、企业服务全覆盖,降本增效,释放创意!
- 53次使用
-
- Suno苏诺中文版
- 探索Suno苏诺中文版,一款颠覆传统音乐创作的AI平台。无需专业技能,轻松创作个性化音乐。智能词曲生成、风格迁移、海量音效,释放您的音乐灵感!
- 57次使用
-
- 详解Go 语言如何通过测试保证质量
- 2022-12-29 290浏览
-
- Golang 单元测试和基准测试实例详解
- 2022-12-23 275浏览
-
- GoLang基础学习之go test测试
- 2023-01-01 265浏览
-
- Golang单元测试与覆盖率的实例讲解
- 2022-12-31 156浏览
-
- golang分层测试之http接口测试入门教程
- 2023-02-16 444浏览