Go语言工程实践单元测试基准测试示例详解
背景
测试的出现是为了避免项目中出现重大事故
测试是避免事故的最后一道屏障
测试
单元测试的覆盖率在一定程度上而言,决定了代码的质量
单元测试
通过测试单元的输出与期望值进行校对从而验证代码的正确性,从而保证新旧代码的互不影响与程序的正常运行。
进而单元测试较于编译更易于在较短的周期内发现和定位代码中的错误使损失最小化从而提升效率。所以写单元测试是很有必要的。
Golang单元测试对文件名和方法名,参数都有很严格的要求。
- 文件名必须以
xx_test.go
命名 - 方法必须是
Test[^a-z]
开头 - 方法参数必须
t *testing.T
- 初始化逻辑放到TestMain中
- 使用
go test
执行单元测试
演示
通过第三方包assert演示单元测试
判断函数测试值与期望值是否一致
import( "github.com/stretchr/testify/assert" "testing" ) func TestHelloTom(t *testing.T) { output := HelloTom() expectOutput := "Tom" assert.Equal(t, expectOutput, output) } func HelloTom() string { return "Tom" }
覆盖率
覆盖率出现的目的:
- 衡量代码是否经过了足够的测试
- 评价项目的测试水准
- 评估项目是否达到了高水准测试等级
通过go test命令测试函数的覆盖率
// judgment.go func JudgePassLine(score int16) bool { if score >= 60 { return true } else { return false } } // judgment_test.go func TestJudgePassLineTrue(t *testing.T) { isPass := JudgeePassLine(70) assert.Equal(t, true, isPass) } func TestJudgePassLineFalse(t *testing.T) { isPass := JudgeePassLine(50) assert.Equal(t, false, isPass) } /* 通过go test 命令测试覆盖率 go test judgment_test.go judgment.go --cover */
一般覆盖率:50%~60%
,较高覆盖率:80%+
测试分支相互独立、全面覆盖
对于上述案例代码而言
应出现成绩大于等于60 和小于60的测试用力
测试单元粒度足够小,函数单一职责
依赖
- 幂等:重复运行同一个case,结果与之前一致
- 稳定:指单元测试相互隔离,可以独立运行
文件处理
当测试文件被修改后,可能会导致测试失败或错误率增高
从而出现了Mock函数
func ReadFirstLine() string { open, err := os.Open("log") // 打开一个文件 defer open.Close() if err != nil { return "" } scanner := bufio.NewScanner(open) // 对每行进行遍历 for scanner.Scan() { return scanner.Text() } return "" } func ProcessFirstLine() string { line := ReadFirstLine() destLine := strings.ReplaceAll(line, "11", "00") // 替换11为00 return destLine } func TestProcessFirstLine(t *testing.T) { // 执行单元测试 firstLine := ProcessFirstLine() assert.Equal(t, "line00", firstLine) }
Mock
monkey: github.com/bouk/monkey 这是一个开源的mock测试库,可以对method或者实例的方法进行mock
Monkey Patch的作用域在Runtime, 运行时通过Go的unsafe包能够将内存中函数的地址替换为运行时函数的地址,将待打桩函数或方法的实现跳转。
Mock函数不仅可以为一个函数打桩 也可以为一个方法打桩
// 用函数A去替换函数B,B就是原函数,A就是打桩函数 func Patch(target, replacement interface{}) *PatchGuard { // target就是原函数,replacement就是打桩函数 t := reflect.ValueOf(target) r := reflect.ValueOf(replacement) patchValue(t, r) return &PatchGuard{t, r} } func Unpatch(target interface{}) bool { // 保证了在测试结束之后需要把这个包卸载掉 return unpatchValue(reflect.ValueOf(target)) } func TestProcessFirstLineWithMock(t *testing.T) { monkey.Patch(ReadFirstLine, func() string { return "line110" }) defer monkey.Unpatch(ReadFirstLine) line := ProcessFirstLine() assert.Equal(t, "line000", line) } // 通过patch对ReadFirstLine进行打桩mock,默认返回line110,通过defer卸载mock // 这样整个测试函数就摆脱了本地文件的束缚和依赖
基准测试
基准测试是指测试一段程序的性能及耗费CPU的程度;
在实际的项目开发中,经常会遇到代码性能瓶颈,为了定位问题,经常要对代码做性能分;
这时就用到了基准测试,其使用方法与单元测试类似。
- 优化代码,需要对当前代码分析
- 内置的测试框架提供了基准测试的能力
小结
对于今日课程而言,我将其划分成测试的重要性与分类。 当前课程余下部分为项目实战,该部分内容选择了放置于项目笔记。 如果笔记中有错误的地方也希望掘友们可以及时的提出纠正,更多关于Go语言单元测试基准测的资料请关注猪先飞其它相关文章!
原文出处:https://juejin.cn/post/7190726245607276600
相关文章
- 在程序员中,尤其是go新手,经常听到的一个讨论话题是:如何处理错误,这篇文章主要给大家介绍了关于Go应用中优雅处理Error的一些相关技巧,需要的朋友可以参考下...2021-09-08
- 这篇文章主要介绍了解决@SpringBootTest 单元测试遇到的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-14
Django def clean()函数对表单中的数据进行验证操作
这篇文章主要介绍了Django def clean()函数对表单中的数据进行验证操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-09- DVWA (Dam Vulnerable Web Application)DVWA是用PHP+Mysql编写的一套用于常规WEB漏洞教学和检测的WEB脆弱性测试程序。包含了SQL注入、XSS、盲注等常见的一些安全漏洞...2016-11-25
- mail()函数的作用:连接到邮件服务器,利用smtp协议,与该服务器交互并投邮件。注意:1、mail函数不支持esmtp协议,---即,只能直投,不能登陆2、由上条,我们只能直投至最终的收件服务器地址.而该地址,又是在PHP.ini中指定的,所...2015-10-30
- 宿主机使用网线的时候,客户机在Bridged Adapter模式下,使用Atheros AR8131 PCI-E Gigabit Ethernet Controller上网没问题。 宿主机使用无线的时候,客户机在Bridged Adapter模式下,使用可选项里唯一一个WIFI选项,Microsoft Virtual Wifi Miniport Adapter也无法上网,故弃之。...2013-09-19
- 这篇文章主要介绍了golang官方嵌入文件到可执行程序,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-20
- 这篇文章主要介绍了go浮点数转字符串保留小数点后N位解决办法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-05-11
- 这篇文章主要介绍了Go语言使用读写OPC详解,图文讲解的很清晰,有感兴趣的同学可以学习下...2021-03-05
- string与[]byte经常需要互相转化,普通转化会发生底层数据的复制,下面这篇文章主要给大家介绍了关于Go中string与[]byte高效互转的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下...2021-09-20
- mail()函数的作用:连接到邮件服务器,利用smtp协议,与该服务器交互并投邮件。注意:1、mail函数不支持esmtp协议,---即,只能直投,不能登陆2、由上条,我们只能直投至最终的收件服务器地址.而该地址,又是在PHP.ini中指定的,所...2015-10-30
- 这篇文章主要介绍了Go项目的目录结构,对基础目录做了讲解,对项目开发中的其它目录也一并做了介绍,需要的朋友可以参考下...2020-05-01
- Go 语言提供的基础容器,免不了要查询容器中的数据,那么是如何实现遍历的呢?本文将会介绍几种常用容易的遍历及其使用。感兴趣的可以了解一下...2021-06-13
- 这篇文章主要介绍了创建第一个Go语言程序Hello,Go!本文详细的给出项目创建、代码编写的过程,同时讲解了GOPATH、Go install等内容,需要的朋友可以参考下...2020-05-01
- 这篇文章主要介绍了在Django中使用MQTT的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-10
- php测试性能代码 function microtime_float () { list ($usec, $sec) = explode(" ", microtime()); return ((float) $usec + (float) $sec); } functio...2016-11-25
- 这篇文章主要介绍了go语言中的Carbon库时间处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-05
- 这篇文章主要介绍了go嵌套匿名结构体的初始化详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-16
- 下面我们一起来看看一篇关于phpmyadmin写入一句话木马的测试教程,希望此教程能够对各位有帮助。 方法一,一句话木马偶尔拿到一个config中,发现是root,且还有phpmyadmi...2016-11-25
解决导入django_filters不成功问题No module named 'django_filter'
这篇文章主要介绍了解决导入django_filters不成功问题No module named 'django_filter',具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-15