go语言单元测试和基准测试
Go test工具
Go语言中测试依赖go test命令。
go test命令是一个按照一定约定和组织的测试代码的驱动程序。在包目录内,所有以_test.go为后缀名的源代码文件都是go test 测试的一部分,不会被go build编译到最终的可执行文件中。
测试函数类型
在*_test.go文件中有三种类型的函数:单元测试函数,基准测试函数和示例函数。
类型 | 格式 | 作用 |
测试函数 | 函数名缀为Test | 测试程序的一些逻辑行为是否正确 |
基准函数 | 函数名前缀为Benchmark | 测试函数的内存占用和运行效率的性能数据 |
示例函数 | 函数名前缀为Example |
为文档提高示例文档 |
测试规则
测试规则主要为文件命名与放置规则:
- 测试源文件名应是_test结尾的go文件,例如:add_test.go;
- 测试代码和业务代码是分开的,但两者应该位于同一包下;
- 测试源文件所在的包应该位于$GOPATH/src目录下;
- 测试文件必须导入"testing"包;
测试函数
每个测试函数必须导入testing包,测试函数的基本格式如下:
1 2 3 | func TestName(t *testing.T){ //... } |
测试函数的名字必须以Test开头,可选的后缀名必须以大写字母开头,举几个例子:
1 2 3 | func TestAdd(t *testing.T){...} func TestSum(t *testing.T){...} func TestLog(t *testing.T){...} |
其中参数t用于报告测试失败和附加的日志信息。testing.T拥有的方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | func (c *T)Error(args ... interface {}) func (c *T)Errorf(format string,args ... interface {}) func (c *T)Fail() func (c *T)Failnow() func (c *T)Failed()bool func (c *T)Fatal(args ... interface {}) func (c *T)Fatal(format string ,args ... interface {}) func (c *T)Log()(args ... interface {}) func (c *T)Logf(format string ,args ... interface {}) func (c *T)Name() string func (c *T)Paralled() func (c *T)Run(name string,f func (t *T)) bool func (c *T)Skip(args ... interface {}) func (c *T)SkipNow() func (c *T)Skipf(format string ,args ... interface {}) func (c *T)Skipped() bool |
go test参数
-bench [正则表达式]:仅运行与正则表达式匹配的基准,默认情况下,不运行基准测试。如果要运行所有的基准测试函数,使用-bench .或者-bench=.。
-benchtime [时间]:表示运行多长时间的基准测试,默认值为1秒。例如:-benchtime 1h30s。
-count n:运行每个测试和基准多少次,默认为1,如果设置了-cpu,则为每个GOMAXPROCS运行n次,例子函数总是运行一次。
-cover:启用覆盖率分析,由于覆盖率通过在编译之前注释源代码来工作,因此启用覆盖率的编译和测试失败,可能会出现报告与原始文件行号不对应的情况。
-covermode set,count,atomic:为正在测试的包设置覆盖率分析模式,除非启用-race,否则默认为set,在这种情况下它是原子的。
set,布尔值,表示这句声明是否有效
count,int类型,这句声明运行多少次
atomic,int类型,在多线程测试中使用,原子操作。
-coverpkg pattern1,pattern2,pattern3:将每个测试中的覆盖率分析应用于模式匹配的包,默认情况下,每个测试仅分析正在测试的包。
-cpu 1,2,4:指定应为其执行测试或基准测试的GOMAXPROCS的值的列表,默认值是GOMAXPROCS的当前值。
-failfast:表示在第一次测试失败后不要开始新的测试。
-list [正则表达式]:只是列出与正则表达式匹配的测试、基准测试或例子,不会运行任何测试。
-parallel n:表示运行的最大测试数,默认情况下,它设置为GOMAXPROCS的值。
-run [正则表达式]:仅仅运行与正则表达式匹配的那些测试和例子,匹配时可能父项也会运行,例如:-run = X/Y,匹配运行所有与X匹配的测试的结果,即使没有匹配到子测试。
-timeout [时间]:如果测试文件运行的时间超过设置的时间,就会出现panic。如果设置的时间为0,则表示timeout不可用。默认是10分钟。
-v:会打印详细的测试结果,即使是在测试成功的情况。
单元测试
1.在src目录下创建mytest目录,创建两个文件Add.go和Add_test.go文件;
Add.go:
1 2 3 4 5 6 7 8 9 | package main func addNum(n int) (result int) { for i := 0; i <= n; i++ { result = result + i } return } |
Add_test.go:
1 2 3 4 5 6 7 8 9 10 11 12 | package main import ( "testing" ) //单元测试函数 func TestAddNum(t *testing.T) { if addNum(100) != 5050 { t.Fatal( "addNum error!" ) } } |
2.进入src目录下的mytest目录下,执行go test命令
3.返回结果
1 2 | PASS ok mytest 0.056s |
加入基准测试
1.修改Add_test.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package main import ( "testing" ) //单元测试函数 func TestAddNum(t *testing.T) { if addNum(100) != 5050 { t.Fatal( "addNum error!" ) } } //基准测试函数 func BenchmarkAddNum(b *testing.B) { for i := 0; i < b.N; i++ { if addNum(100) != 5050 { b.Fatal( "addNum" ) } } } |
2.执行go test -bench=.
3.返回结果
1 2 3 4 5 6 | goos: windows goarch: amd64 pkg: MyDemo/mytest BenchmarkAddNum-4 20000000 74.3 ns/op PASS ok mytest 1.615s |
显示执行addNum函数花费的平均时间是1.615s,执行了20000000次,每74.3ns的速度运行一次循环。
特殊功能
指定基准测试函数:通过-bench可以指定只测试哪个基准函数,如果没有指定,则测试所有基准函数。
1 | go test -bench=. 测试所有基准函数 go test -bench=Alloc 指定只测试Benchmark_Alloc() 基准函数 |
自定义测试时间:通过-benchtime
参数可以自定义测试时间。(基准测试原理:基准测试框架对一个测试用例的默认测试时间是 1 秒。开始测试时,当以 Benchmark 开头的基准测试用例函数返回时还不到 1 秒,那么 testing.B 中的 N 值将按 1、2、5、10、20、50……递增,同时以递增后的值重新调用基准测试用例函数。)
1 | go test -v -bench=. -benchtime=5s |
测试内存:基准测试可以对一段代码可能存在的内存分配进行统计:通过-benchmem
参数以显示内存分配情况。
1 | go test -bench=. -benchmem |
1 2 3 4 5 | 返回信息字段:<br>Benchmarkxxx-4 格式为基准测试函数名-GOMAXPROCS,后面的-4代表测试函数运行时对应的CPU核数 1 表示执行的次数 xx ns/op 表示每次的执行时间 xx B/op 表示每次执行分配的总字节数(内存消耗) xx allocs/op 表示每次执行发生了多少次内存分配 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2019-02-15 Shell学习之结合正则表达式与通配符的使用(五)
2019-02-15 Linux学习之后台任务与定时任务(二十)
2019-02-15 Linux学习之进程管理(十九)