Golang单元测试
测试文件一般以xxx_test.go
,代表测试xxx.go
文件中的函数功能。
单元测试都需要:
- 正常执行
- 异常例子
- 正常与异常的边界例子
- 追求分支覆盖
- 追求代码覆盖
单元功能测试
功能测试函数名称以Test
开头
1 | func TestGetArea(t *testing.T) { |
执行方式
1 | go test -v |
快速生成测试用例
通过Goland
编译器可以快速生成单元测试模板,在代码文件中,通过快捷键command+N
呼出生成菜单,选择生成文件测试生成对应文件中方法的测试,或者选择软件包测试,生成包的测试。
基准测试(性能压力测试)
性能压力测试函数名称以Benchmark
开头
1 | func BenchmarkGetArea(b *testing.B) { |
执行方式
1 | go test -bench=. |
代码覆盖率测试
代码覆盖率测试可以实现在测试过程检查覆盖到的代码
执行方式
1 | go test -cover |
也可以将测试情况输出到文件
1 | go test -coverprofile=./cover.out |
通过字符展示
1 | go tool cover -func=./cover.out |
或者通过页面图形化展示
1 | go tool cover -html=./cover.out |
子测试
单元测试中,支持将一些测试集中在一起,作为一个单元测试的集合。
1 | func TestCalc(t *testing.T) { |
执行结果
1 | # go test -v |
表驱动测试
表驱动测试可以很好的覆盖到多种测试场景
1 | func TestCalc(t *testing.T) { |
帮助函数
t.Helper()
帮助函数,标注该函数是帮助函数,报错时,将输出帮助函数调用者的信息,而不是帮助函数的内部信息。
1 | type Case struct { |
运行结果
1 | === RUN TestCalc |
顺序逻辑测试
函数testMain
,当有testMain
函数时,会执行testMain
函数,在testMain
中的m.Run
会将其他的单元测试函数按照顺序执行。如果有需要事先准备的函数或者事后清理的函数,也会按照顺序执行
1 | func prepare() { |
通过go test -v
输出
1 | start |
web测试
通过httptest
包测试http.handler
函数
1 | func ping(rw http.ResponseWriter, req *http.Request) { |
测试函数
1 | func TestHttp(t *testing.T) { |
测试性能
1 | func BenchmarkHttp(b *testing.B) { |
若是使用框架启动http
服务,例如通过Gin
框架实现http
服务
1 | func UserList(c *gin.Context) { |
通过httptest
测试
1 | func TestUserList(t *testing.T) { |
此时并没有http
服务启动起来,直接测试的heanlder
函数。
通过发送http
请求测试服务
1 | func TestHttpConn(t *testing.T) { |
gotests
测试自动代码生成,gotests
安装
1 | go get -u github.com/cweill/gotests/... |
用法
1 | -all 对所有函数和方法生成 |
1 | gotests -all ./ > demo1_test.go |
生成的测试代码,自动使用表驱动测试
1 | package demotest |
如果当前目录下已经有测试文件,通过gotests
生成的测试代码会仿照已存在的测试文件模板。
示例函数
在其他包调用函数时,IED会将示例展示出来,godoc
文档服务器也会将示例展示出来。
1 | func ExampleAdd() { |
展示效果
1 | Example |
mock测试
当待测试的函数、对象的依赖关系很复杂,并且有些依赖不能直接创建,例如数据库连接、文件IO等,这种场景就非常适合使用mock/stub
测试。用mock
对象模拟依赖项的行为。
面向数据库连接mock测试
使用mysql
或者pgsql
是一样的,选择对应驱动即可
安装go-sqlmock
1 | github.com/DATA-DOG/go-sqlmock |
官方的例子可查看:go-sqlmock
pgsql
1 | package mysql |
mock
测试
1 | package mysql |
测试结果
1 | === RUN Test_UpdateViews |
redis测试
官方文档和示例:miniredis
安装miniredis
1 | go get github.com/alicebob/miniredis/v2 |
redis功能
1 | package redis |
单元测试
1 | package redis |
面向接口mock测试
mock
推荐阅读
安装
1 | go install github.com/golang/mock/[email protected] |
例如测试通过数据库获取信息,模拟测试接口
1 | package db |
为GetFromDB
函数生成单元测试代码,就可以通过mock
这个DB
来测试
1 | mockgen -source=db.go -destination=mocks/db_mock.go -package=mocks |
在本地生成一个mocks
目录,里面有db_mock.go
文件
在单元测试中引用mocks
包中的方法即可
1 | package db |
模糊测试
Golang
1.18版本开始引入模糊测试(Go Fuzz
),使用方法与单元测试一样,相比单元测试,模糊测试集成了各项测试用例,可以测试出一些想象不到的、边界情况下的问题。
1 | func Equal(a []byte, b []byte) bool { |
上面的例子,当出现out fo range
的情况就无法测试出来
1 | func FuzzEqual(f *testing.F) { |
运行测试
1 | # go test -v -fuzztime=10s -fuzz . // -fuzz . 使用fuzz测试,-fuzztime=10s 表示测试时间 |
可以看到fuzz
测试会模拟一些情况index out of range [0] with length 0
修改Equal
函数代码
1 | func Equal(a []byte, b []byte) bool { |
再次测试
1 | go test -v -fuzztime=10s -fuzz . |
推荐阅读:
fuzz测试