摘要:测试对于互联网应用软件开发来说非常重要,它对软件可靠性保证具有重要意义,通过测试能够尽可能发现并改正软件中的错误,提高软件质量。这里我们主要讲解语言如何实现单元测试和性能测试。单元测试创建目录,在目录下创建两个文件,为单元测试文件。
测试对于互联网应用软件开发来说非常重要,它对软件可靠性保证具有重要意义,通过测试能够尽可能发现并改正软件中的错误,提高软件质量。
这里我们主要讲解Go语言如何实现单元测试和性能测试。
go语言中自带有一个轻量级的测试框架testing和自带的go test命令来实现单元测试和性能测试,testing框架和其他语言中的测试框架类似,你可以基于这个框架写针对相应函数的测试用例,也可以基于该框架写相应的压力测试用例,那么接下来让我们一一来看一下怎么写。
单元测试
创建目录test,在目录下创建add.go、add_test.go两个文件,add_test.go为单元测试文件。
add_test.go
package test import "testing" func TestAdd(t *testing.T) { sum := Add(1, 2) if sum == 3 { t.Log("the result is ok") } else { t.Fatal("the result is wrong") } } func TestAdd1(t *testing.T) { t.Error("the result is error") }
add.go
package test func Add(a, b int) int { return a + b }
然后在项目目录下运行go test -v就可以看到测试结果了
=== RUN TestAdd --- PASS: TestAdd (0.00s) add_test.go:8: the result is ok === RUN TestAdd1 --- FAIL: TestAdd1 (0.00s) add_test.go:14: the result is error FAIL exit status 1 FAIL _/D_/gopath/src/ados/test 0.419s
如果看到PASS字样证明测试通过,FAIL字样表示测试失败。
使用testing库的测试框架需要遵循以下几个规则如下:
文件名必须是_test.go结尾的,这样在执行go test的时候才会执行到相应的代码
你必须import testing这个包
所有的测试用例函数必须是Test开头
测试用例会按照源代码中写的顺序依次执行
测试函数TestXxx()的参数是testing.T,我们可以使用该类型来记录错误或者是测试状态
测试格式:func TestXxx (t *testing.T),Xxx部分可以为任意的字母数字的组合,但是首字母不能是小写字母[a-z],例如Testintdiv是错误的函数名。
函数中通过调用testing.T的Error, Errorf, FailNow, Fatal, FatalIf方法,说明测试不通过,调用Log方法用来记录测试的信息。
性能测试或压力测试
压力测试用来检测函数(方法)的性能,和编写单元功能测试的方法类似,此处不再赘述,但需要注意以下几点:
压力测试用例必须遵循如下格式,其中XXX可以是任意字母数字的组合,但是首字母不能是小写字母
func BenchmarkXXX(b *testing.B) { ... }
go test不会默认执行压力测试的函数,如果要执行压力测试需要带上参数-test.bench,语法:-test.bench="test_name_regex",例如go test -test.bench=".*"表示测试全部的压力测试函数
在压力测试用例中,请记得在循环体内使用testing.B.N,以使测试可以正常的运行
文件名也必须以_test.go结尾
在test目录下创建 reflect_test.go
package test import ( "reflect" "testing" ) type Student struct { Name string Age int Class string Score int } func BenchmarkReflect_New(b *testing.B) { var s *Student sv := reflect.TypeOf(Student{}) b.ResetTimer() for i := 0; i < b.N; i++ { sn := reflect.New(sv) s, _ = sn.Interface().(*Student) } _ = s } func BenchmarkDirect_New(b *testing.B) { var s *Student b.ResetTimer() for i := 0; i < b.N; i++ { s = new(Student) } _ = s } func BenchmarkReflect_Set(b *testing.B) { var s *Student sv := reflect.TypeOf(Student{}) b.ResetTimer() for i := 0; i < b.N; i++ { sn := reflect.New(sv) s = sn.Interface().(*Student) s.Name = "Jerry" s.Age = 18 s.Class = "20005" s.Score = 100 } } func BenchmarkReflect_SetFieldByName(b *testing.B) { sv := reflect.TypeOf(Student{}) b.ResetTimer() for i := 0; i < b.N; i++ { sn := reflect.New(sv).Elem() sn.FieldByName("Name").SetString("Jerry") sn.FieldByName("Age").SetInt(18) sn.FieldByName("Class").SetString("20005") sn.FieldByName("Score").SetInt(100) } } func BenchmarkReflect_SetFieldByIndex(b *testing.B) { sv := reflect.TypeOf(Student{}) b.ResetTimer() for i := 0; i < b.N; i++ { sn := reflect.New(sv).Elem() sn.Field(0).SetString("Jerry") sn.Field(1).SetInt(18) sn.Field(2).SetString("20005") sn.Field(3).SetInt(100) } } func BenchmarkDirect_Set(b *testing.B) { var s *Student b.ResetTimer() for i := 0; i < b.N; i++ { s = new(Student) s.Name = "Jerry" s.Age = 18 s.Class = "20005" s.Score = 100 } }
在test目录下,执行:
go test reflect_test.go -test.bench=".*"
结果如下
goos: windows goarch: amd64 BenchmarkReflect_New-4 20000000 84.9 ns/op BenchmarkDirect_New-4 30000000 50.6 ns/op BenchmarkReflect_Set-4 20000000 89.9 ns/op BenchmarkReflect_SetFieldByName-4 3000000 552 ns/op BenchmarkReflect_SetFieldByIndex-4 10000000 132 ns/op BenchmarkDirect_Set-4 30000000 53.0 ns/op PASS ok command-line-arguments 10.982s
上面的结果显示我们没有执行任何TestXXX的单元测试函数,显示的结果只执行了压力测试函数,以第三行为例
BenchmarkReflect_New 函数执行了20000000次,每次的执行平均时间是84.9纳秒。最后一行 command-line-arguments 10.982s,代表总的执行时间为 10.982s。
如果只想对某个函数测试,以BenchmarkReflect_New 为例,执行命令
go test reflect_test.go -test.bench="BenchmarkReflect_New"
结果为:
goos: windows goarch: amd64 BenchmarkReflect_New-4 20000000 84.9 ns/op PASS ok command-line-arguments 2.490s
如果测试整个目录下的所有测试执行:
go test -test.bench=".*"
如果想显示内存分配的次数和大小添加 -benchmem
go test reflect_test.go -benchmem -test.bench=".*"
goos: windows goarch: amd64 BenchmarkReflect_New-4 20000000 88.3 ns/op 48 B/op 1 allocs/op BenchmarkDirect_New-4 30000000 53.8 ns/op 48 B/op 1 allocs/op BenchmarkReflect_Set-4 20000000 90.9 ns/op 48 B/op 1 allocs/op BenchmarkReflect_SetFieldByName-4 3000000 564 ns/op 80 B/op 5 allocs/op BenchmarkReflect_SetFieldByIndex-4 10000000 135 ns/op 48 B/op 1 allocs/op BenchmarkDirect_Set-4 30000000 52.4 ns/op 48 B/op 1 allocs/op PASS ok command-line-arguments 12.955s
后两列代表分配的内存大小和次数(48 B/op 1 allocs/op)
推荐gotests
它是编写Go测试的一个Golang命令行工具,可以根据目标源文件的函数和方法签名生成表驱动的测试。将自动导入测试文件中的任何新依赖项。
参考:
https://studygolang.com/stati...
https://www.cnblogs.com/yjf51...
links目录
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/8916.html
摘要:最近在维护一个三年前的旧代码,用的是框架。单元测试和语言并发控制实际上是个蛋疼的问题,夸张一点说,当时的并不能特别轻松地实现并发,甚至不能实现并发。语言的功能之一就是自带单元测试。用语言之前,我的习惯是不写单元测试。 最近在维护一个三年前的旧代码,用的是laravel框架。 从某些方面来讲,这个代码算是比较标准为了实现在规定的时间内完成相关功能,同时程序员水平不高、经过大量优化之后,变...
摘要:是语言编写的用于操作文档类库,基于标准。可以使用它来读取写入由及以上版本创建的文档。年月日,社区正式发布了版本,该版本包含了很多新功能错误修复和性能优化。 showImg(https://segmentfault.com/img/remote/1460000018971694?w=880&h=360); Excelize 是 Go 语言编写的用于操作 Office Excel 文档类库...
摘要:持续交付持续交付豆瓣微服务离不开,而核心就是几点自动化连续小范围快速可靠。敏捷革命敏捷革命提升个人创造力与企业效率的全新协作模式豆瓣实际上正是敏捷开发的最佳实践,有了前面的铺垫,我们可以通过这本书我们来真正了解敏捷开发的全貌。 后端好书阅读与推荐系列文章: 后端好书阅读与推荐后端好书阅读与推荐(续)后端好书阅读与推荐(续二)后端好书阅读与推荐(续三)后端好书阅读与推荐(续四)后端好书...
摘要:功能测试函数功能测试函数需要接收类型的单一参数,类型用来管理测试状态和支持格式化的测试日志。测试函数的相关说明,可以通过来查看帮助文档。下面是一个例子被测试的进程退出函数测试进程退出函数的测试函数参考资料原文链接 原文链接:http://tabalt.net/blog/golang... Golang作为一门标榜工程化的语言,提供了非常简便、实用的编写单元测试的能力。本文通过Golan...
阅读 3197·2023-04-25 18:43
阅读 862·2021-11-24 09:39
阅读 1340·2021-10-14 09:43
阅读 3866·2021-09-22 15:58
阅读 1830·2019-08-29 17:18
阅读 371·2019-08-29 14:14
阅读 3048·2019-08-29 13:01
阅读 1575·2019-08-29 12:33