Go测试|青训营笔记

103 阅读3分钟

这是我参与「第五届青训营 」笔记创作活动的第4天

主要内容

  • 单元测试
  • Mock测试
  • 基准测试

单元测试

输入测试单元得到输出,与期望值做一个校对

单元测试-规则

  • 所有测试文件以_test.go结尾
  • 函数命名为func TestXxx(*testing.T)
  • 初始化逻辑放到函数TestMain中

单元测试-例子

```
package unit_testing

func HelloTom() string {//正确的情况应该是返回"Tom"
   return "han"
}
```

测试文件

```
package unit_testing

import "testing"

func TestHelloTom(t *testing.T) {
   output := HelloTom()
   expectOutput := "Tom"
   if output != expectOutput {
      t.Errorf("预期为%v,而不是%v", expectOutput, output)
   }
}
```

go test运行得到结果:

=== RUN   TestHelloTom
    HelloTom_test.go:9: 预期为Tom,而不是han
--- FAIL: TestHelloTom (0.00s)

FAIL


Process finished with the exit code 1

单元测试-assert

前面我们在验证是否相等时使用的是"!="运算符,我们也可以使用一些包来比较

先导包(视频里没有),在终端运行: go get github.com/stretchr/testify/assert

image.png 修改后的代码

```
package unit_testing

import (
   "github.com/stretchr/testify/assert"
   "testing"
)

func TestHelloTom(t *testing.T) {
   output := HelloTom()
   expectOutput := "Tom"
   //if output != expectOutput {
   // t.Errorf("预期为%v,而不是%v", expectOutput, output)
   //}
   assert.Equal(t, expectOutput, output)
}
```

再次执行go test

PS D:\code\Golang\src\qxy\practice\unit_testing> go test
--- FAIL: TestHelloTom (0.00s)
    HelloTom_test.go:14:
                Error Trace:    D:\code\Golang\src\qxy\practice\unit_testing\HelloTom_test.go:14
                Error:          Not equal:
                                expected: "Tom"
                                actual  : "han"

                                Diff:
                                --- Expected
                                +++ Actual
                                @@ -1 +1 @@
                                -Tom
                                +han
                Test:           TestHelloTom
FAIL
exit status 1
FAIL    qxy/practice/unit_testing       0.185s
PS D:\code\Golang\src\qxy\practice\unit_testing> 

单元测试-覆盖率

用来衡量代码测试程度的指标

我们在终端执行: go test HelloTom_test.go HelloTom.go --cover 即可获得代码覆盖率

刚刚代码执行得到的覆盖率的结果:100%

image.png 我们尝试在HelloTom.go添加一个在测试中没有使用的函数,再次执行测试,得到覆盖率结果为:50%

image.png

单元测试-tips

  • 一般覆盖率:50%-60%,较高覆盖率80%+
  • 测试分支相对独立、全面覆盖
  • 测试单元粒度足够小,函数单一原则

单元测试-依赖

外都依赖=>稳定&幂等

外部依赖包括文件、数据库、Cache等

幂等:指多次测试得到的结果应该是一致的

稳定:指单元测试间是相互隔离的,我们可以在任何时间去执行独立的测试单元

Mock

单元测试-Mock

在上面单元测试-依赖中,如果我们依赖的是外部文件,那么如果外部文件被修改,那么我们就无法进行正常的测试,这时我们就引入Mock,即打桩测试,原理是运行时将原函数的指针指向一个新的地址

以开源框架monkey为例(GitHub - bouk/monkey: Monkey patching in Go)

核心的函数Patch

```
// Patch replaces a function with another
func Patch(target, replacement interface{}) *PatchGuard {//这个函数会在运行时将target替换为replacement
   t := reflect.ValueOf(target)
   r := reflect.ValueOf(replacement)
   patchValue(t, r)

   return &PatchGuard{t, r}
}
```

当我们调用完Patch函数后,需要调用Unpatch函数来卸载包函数

```
// Unpatch removes any monkey patches on target
// returns whether target was patched in the first place
func Unpatch(target interface{}) bool {
   return unpatchValue(reflect.ValueOf(target))
}
```

这样的测试可以在任何时间,任何环境测试,完全不依赖本地文件

基准测试

基准测试和单元测试差不多,测试的是程序运行时cpu的性能

  • 函数命名为func BeachmarkXxx(*testing.B)