《Go 单元测试从入门到覆盖率提升》(二)

[复制链接]
发表于 2025-9-27 07:56:08 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
 
Golang相干测试框架

  在 Go 语言里,最常用的测试框架有:自带的 testing 包、GoConvey 和 testify。
1、Go自带的testing包

   testing 包是官方内置的,无需额外安装,也是大多数项目标首选。
  (1)单元测试


  • 测试文件必须以 _test.go 末了,比方:calc_test.go
  • 测试函数必须以 Test 开头(保举写成 Test+函数名,更直观)
  • 测试函数署名固定:func TestXxx(t *testing.T),不能有返回值
  • 测试函数内部用 t.Errorf / t.Fatal 等方法输堕落误

    • t.Errorf:标记测试失败,但 继承实验背面的测试代码。
    • t.Fatal:标记测试失败,并 立即停止当前测试函数。

  1. # 执行当前目录下所有 *_test.go 文件
  2. go test -v
  3. # 只执行指定文件中的测试
  4. go test -v calc_test.go calc.go
  5. # 执行指定的测试函数(-count=1 表示禁用缓存,强制重新运行)
  6. go test -v -run TestAdd calc_test.go calc.go -count=1
复制代码
  更详细的参数请参考:Go test下令行参数  (2)性能测试


  • 文件定名:和单测一样,文件必须以 _test.go 末了,如许 go test 才华辨认。
  • 函数定名:基准测试函数要以 Benchmark 开头,且必须是导出函数,比如 BenchmarkAdd。
  • 函数署名:基准测试函数必须吸收一个 *testing.B 范例的参数,不能有返回值。
  • 重置计时器:b.ResetTimer() 用来清空前面初始化代码的耗时,包管只统计真正的测试部分。
  • 循环实验:基准测试里要用 for i := 0; i < b.N; i++ { ... },被测的代码放在循环里。
  • b.N 的作用:Go 框架会自动调解 b.N,让测试至少运行 1 秒左右,如许结果更稳固。终极输出的是匀称每次运行的耗时(比如 0.25 ns/op 表现每次 0.25 纳秒)。
  在calc文件夹的calc_test.go文件中新增BenchmarkAbs和BenchmarkAdd方法。

   基准测试的目标就是 尽大概正确地衡量一段代码的性能,包罗运行时间、内存分配等。

  • 焦点思绪:同一段代码运行很多次(b.N 次),用「总耗时 ÷ b.N」算出匀称每次实验的耗时。
  • b.N 的作用:b.N 由 Go 测试框架自动决定,会动态调解,包管测试至少运行 1 秒左右,制止样本太少导致结果禁绝。
  • 运行过程:当实验 go test -bench=. 时,框架会先用很小的 b.N(比如 1、2、5、19)试跑频频,估算耗时,再渐渐增大 b.N,直到结果稳固。
  • 输出示例:比如陈诉里写 1000000000 0.25 ns/op,意思是运行了 10 亿次,每次匀称耗时 0.25 纳秒。

 

 
  1. # 运行所有基准测试
  2. go test -bench=.
  3. # 运行所有基准测试并显示内存分配情况
  4. go test -bench=. -benchmem
  5. # 只运行基准测试,不运行单元测试
  6. go test -run=none -bench=.
  7. # 指定测试时间
  8. go test -bench=. -benchtime=3s
  9. # 指定运行轮数
  10. go test -bench=. -count=3
  11. # 组合使用多种参数
  12. go test -run=none -bench=. -benchmem -benchtime=3s -count=3
复制代码
2、GoConvey

https://github.com/smartystreets/goconvey  GoConvey 是一款专门为 Golang 打造的测试框架,它不但能帮你更方便地构造和运行单元测试,还自带了丰富的断言方法,让测试代码更简便直观。更酷的是,它还支持 Web 界面:只要在项目里写好测试,用 go test 下令就能照常运行;如果你想要更直观的体验,可以直接运行 goconvey,然后在欣赏器里访问 http://localhost:8080,就能看到实时的测试结果展示。  相比起纯粹使用标准库的 testing 包,Convey 让单元测试的誊写和阅读都更流畅,尤其得当必要频仍跑测试、调试逻辑的开发过程。
  (1)安装依赖:go get github.com/smartystreets/goconvey

  (2)demo


 

 
3、testify

  Testify 是 Go 语言生态里非常常用的一个 断言风格测试框架。它不但提供了开发者最常用的断言方法(让测试代码更简便、可读性更强),还额外封装了三个焦点功能模块:

  • Assertions(断言):内置了丰富的断言方法,制止重复编写样板式判断逻辑。
  • Suite(测试套件):支持将一组相干测试构造在一起,方便共享初始化、清算等逻辑。
  • Mock(模拟):提供强大的 Mock 本领,方便在单元测试中模拟依赖对象或外部接口。
  借助 Testify,我们可以用更靠近自然语言的方式编写测试,不但进步开发服从,也让测试结果更易于明确。
官方文档:https://godoc.org/github.com/stretchr/testify  (1)依赖安装:go get -u -v github.com/stretchr/testify

  (2)测试用例

  ① assert包提供了断言工具,在实验时会将case标记为失败,但步调不会退出,而是继承往下实验。
  1. package testify
  2. import (
  3.     "testing"
  4.     "github.com/stretchr/testify/assert"
  5. )
  6. func Test_assert(t *testing.T) {
  7.     a := 2
  8.     b := 3
  9.     // 第一个断言失败(故意写错期望值)
  10.     assert.Equal(t, 6, a+b, "第一个断言:2+3应该等于5,不是6")
  11.     // 程序继续执行下面的断言
  12.     t.Log("这行代码被执行了,说明程序没有中断")
  13.     // 第二个断言通过
  14.     assert.Equal(t, 5, a+b, "第二个断言:2+3应该等于5")
  15.     // 第三个断言也会执行
  16.     assert.True(t, a < b, "第三个断言:2应该小于3")
  17.     t.Log("所有断言都已执行完毕")
  18. }
复制代码

   ② require包提供与asser包雷同的全局函数,与assert差别的是,require会制止当前测试。
  1. package testify
  2. import (
  3.     "testing"
  4.     "github.com/stretchr/testify/require"
  5. )
  6. func Test_require(t *testing.T) {
  7.     name := "Tom"
  8.     age := 18
  9.     // 这个会失败并停止测试
  10.     require.Equal(t, "dazuo", name, "测试会在这里停止")
  11.     require.Equal(t, 18, age, "测试会在这里停止")
  12.     // 这行不会被执行
  13.     t.Log("这行代码不会被执行")
  14. }
复制代码

   ③ mock包提供了一种轻松编写模拟对象的机制,可以在编写测试代码时替换实际对象使用模拟对象。
  1. func Test_mock(t *testing.T) {
  2.     // 创建模拟对象
  3.     mockS := &mockStorage{}
  4.     // 设置对Store方法期望的调用,参数必须匹配;返回该方法调用时的返回值
  5.     mockS.On("Store", "name", "Tom").Return(1, nil).Once()
  6.     result, err := mockS.Store("name", "Tom")
  7.     assert.NoError(t, err)
  8.     assert.Equal(t, 1, result)
  9.     mockS.AssertExpectations(t) // 断言所有预期的调用都发生了
  10. }
复制代码

   若该方法没有被调用:
  1. func Test_mock(t *testing.T) {
  2.     // 创建模拟对象
  3.     mockS := &mockStorage{}
  4.     // 设置对Store方法期望的调用,参数必须匹配;返回该方法调用时的返回值
  5.     mockS.On("Store", "name", "Tom").Return(1, nil).Once()
  6.     mockS.AssertExpectations(t) // 断言所有预期的调用都发生了
  7. }
复制代码

 
 
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表