单元测试有很多技巧和科技,我都会缓缓汇总在这里

打桩测试

当咱们在编写单元测试的时候,有时咱们十分想 mock 掉其中一个办法,然而这个办法又没有接口去定义和实现(无奈用 github.com/golang/mock 来实现),这时就能够尝试看看咱们的打桩黑科技。

代码

这里咱们应用 github.com/agiledragon/gomonkey 来实现。

理论中,常常在代码中会遇到一些随机值的状况,比方验证码。为了不便测试,咱们会想要 mock 掉随机值办法,让每次产生的值固定不便后续的测试。

package mainimport (  "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.gogoos: darwingoarch: arm64BenchmarkPrimeNumbers/calc_num_100-8             3391329               348.9 ns/opBenchmarkPrimeNumbers/calc_num_1000-8             293733              3979 ns/opBenchmarkPrimeNumbers/calc_num_77777-8               730           1619089 ns/opBenchmarkPrimeNumbers/calc_num_666666-8               42          28509805 ns/opPASSok      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.outok      go-demo/m/unit-test/service     0.108s  coverage: 70.0% of statements➜ go tool cover -html=cover.out

当然,如果你和我一样应用 goland 进行开发,能够间接在界面上点击单元测试,就能够疾速进行覆盖率测试,并且展现也很不便,很快能看到有哪些代码没有被测试笼罩。

表格驱动测试

TDT 的提出也算是给单元测试提供了一条不错的思路。次要的模式就是将测试的数据做成相似表格,而后测试的时候遍历所有的数据来进行测试,测试代码不动,只须要减少测试数据就能够了。go 很多官网库用了这样的写法来做测试。

package mainimport (    "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 来帮忙咱们疾速生成想要的表格驱动测试代码