Golang单元测试中的技巧分享

作者:LinkinStar 时间:2024-04-23 09:47:32 

打桩测试

当我们在编写单元测试的时候,有时我们非常想 mock 掉其中一个方法,但是这个方法又没有接口去定义和实现(无法用 github.com/golang/mock 来实现),这时就可以尝试看看我们的打桩黑科技。

代码

这里我们使用 github.com/agiledragon/gomonkey 来实现。

实际中,经常在代码中会遇到一些随机值的情况,比如验证码。为了方便测试,我们会想要 mock 掉随机值方法,让每次产生的值固定方便后续的测试。

package main

import (
 "fmt"
 "testing"

"github.com/agiledragon/gomonkey/v2"
 "go-demo/m/unit-test/other/rand"
)

func init() {
 gomonkey.ApplyFunc(rand.Number, func() int { return 666 })
}

func TestRand(t *testing.T) {
 fmt.Println(rand.Number())
}

其中 rand.Number() 是我们在另一个包中实现的方法。我们使用 gomonkey.ApplyFunc 相当于直接替换了原有方法的实现,强制返回了 mock 的数据 666。

注意事项

  • 使用 gomonkey 时,注意一定要使用 -gcflags=all=-l 来禁止内联优化,否则容易导致打桩不生效。如:go test -gcflags=all=-l -v

  • 在 Mac 的 M1 下打桩不生效,可以使用环境变量 GOARCH=amd64 来进行测试,只不过这样就无法进行断点调试。https://github.com/agiledragon/gomonkey/issues/77

  • 毕竟是黑科技,实际使用环境对于测试还是有影响的。

压测

这里的压测通常不是对接口的压测,而是对于某些方法的压测。Golang 提供 非常好用的 b *testing.B 来专门进行压测。

代码

非常容易上手,让我们直接来看代码

var numbers = []int{
 100,
 1000,
 77777,
 666666,
}

func BenchmarkPrimeNumbers(b *testing.B) {
 for _, v := range numbers {
   b.Run(fmt.Sprintf("calc_num_%d", v), func(b *testing.B) {
     for i := 0; i < b.N; i++ {
       primeNumbers(v)
     }
   })
 }
}

使用

使用 -bench=. 即可

➜ go test -bench=. b_test.go
goos: darwin
goarch: arm64
BenchmarkPrimeNumbers/calc_num_100-8             3391329               348.9 ns/op
BenchmarkPrimeNumbers/calc_num_1000-8             293733              3979 ns/op
BenchmarkPrimeNumbers/calc_num_77777-8               730           1619089 ns/op
BenchmarkPrimeNumbers/calc_num_666666-8               42          28509805 ns/op
PASS
ok      command-line-arguments  5.846s

可以看到次数和耗时,这样的数据经常会被贴在开源项目README的性能比较板块中。

测试覆盖率

单元测试当然少不了覆盖率咯,看着高高的覆盖率才有成就感对不对?

我们可以使用 -cover 参数来统计单元测试的代码覆盖率

➜ go test -cover .           
ok      go-demo/m/unit-test/service     0.879s  coverage: 70.0% of statements

还可以生成 profile 然后通过可视化网页查看分析

➜ go test ./... -coverprofile=cover.out
ok      go-demo/m/unit-test/service     0.108s  coverage: 70.0% of statements
➜ go tool cover -html=cover.out

当然,如果你和我一样使用 goland 进行开发,可以直接在界面上点击单元测试,就可以快速进行覆盖率测试,并且展示也很方便,很快能看到有哪些代码没有被测试覆盖。

Golang单元测试中的技巧分享

Golang单元测试中的技巧分享

表格驱动测试

TDT 的提出也算是给单元测试提供了一条不错的思路。主要的形式就是将测试的数据做成类似表格,然后测试的时候遍历所有的数据来进行测试,测试代码不动,只需要增加测试数据就可以了。go 很多官方库用了这样的写法来做测试。

package main

import (
   "testing"
)

func TestAdd(t *testing.T) {
   tests := []struct {
       a, b, expected int
   }{
       {1, 2, 3},
       {0, 0, 0},
       {-1, 1, 0},
       {-1, -1, -2},
   }

for _, test := range tests {
       result := Add(test.a, test.b)
       if result != test.expected {
           t.Errorf("Add(%d, %d) = %d; expected %d", test.a, test.b, result, test.expected)
       }
   }
}

func Add(a, b int) int {
   return a + b
}

我们可以通过 github.com/cweill/gotests 来帮助我们快速生成想要的表格驱动测试代码

来源:https://segmentfault.com/a/1190000043526318

标签:Golang,单元测试
0
投稿

猜你喜欢

  • 简单谈谈MySQL数据透视表

    2024-01-25 05:42:07
  • python绘制BA无标度网络示例代码

    2021-05-29 14:01:52
  • python的简单四则运算语法树可视化

    2023-08-16 09:22:37
  • 多个datatable共存造成多个表格的checkbox都被选中

    2024-05-11 09:18:42
  • GO语言实现列出目录和遍历目录的方法

    2024-05-10 10:58:20
  • golang简单获取上传文件大小的实现代码

    2024-05-21 10:22:09
  • requests在python中发送请求的实例讲解

    2022-06-26 09:04:07
  • python基于property()函数定义属性

    2022-11-01 04:55:14
  • 在微信小程序中获取用户位置的详细过程

    2024-04-29 13:43:02
  • MySql 5.6.14 Win32位免安装解压缩版配置教程

    2024-01-13 01:27:44
  • 培养色感的一些经验分享

    2013-11-10 03:47:03
  • Golang操作sqlite3数据库的详细教程

    2024-01-14 05:32:52
  • expdp 中ORA-39002、ORA-39070错误详解及解决办法

    2024-01-19 16:37:47
  • python实现的简单FTP上传下载文件实例

    2022-12-29 13:17:42
  • 讲解Python中for循环下的索引变量的作用域

    2022-11-27 18:41:05
  • Python中eval带来的潜在风险代码分析

    2023-05-24 03:29:03
  • Python实现获取前100组勾股数的方法示例

    2022-07-14 08:54:23
  • MYSQL数据库Innodb 引擎mvcc锁实现原理

    2024-01-21 08:47:42
  • Python中利用sorted()函数排序的简单教程

    2022-09-13 20:26:36
  • mysql 5.7以上版本安装配置方法图文教程(mysql 5.7.12\\mysql 5.7.13\\mysql 5.7.14)

    2024-01-17 23:14:46
  • asp之家 网络编程 m.aspxhome.com