【go】初识单测
提升代码可测性
- 让函数变小,结果可以直接验证:拆成几个函数
- 让函数依赖变小。
- 保障测试稳定/有效性。
- 被测函数以外的代码进行隔离和保障(测试替身)。
- 真实实现 替代实现stub/fake 模拟实现Mock
- stub:测试桩,通过一种替代的实现来确保被测依赖的逻辑能够得到一个固定的返回。
- Stub: For replacing a method with code that returns a specified result
- stub 是对指定对象方法的重写,返回一个预设的值。
- stub 是伪造方法
- Mock:通过各种框架将依赖实现替换成模拟的实现。和写一个接口其实没什么区别,只不过依赖了Mock的框架。
- A stub with an expectations that the method gets called.
- mock 是用来替代真实对象的测试对象,也被称为测试替身 (test double)。
- mock 是伪造对象
Go单元测试
框架
- 可以用gotest
- go test
- 查看结果
- testify + gomonkey + httptest/gRPC-Go
- gomonkey5种常见用法
- 函数Mock
- 对对象方法mock
- 全局变量Mock
- 封装顺手的脚手架
用例设计
- 3A模板
- 准备:第一个A(rrange)里,我们会准备好测试各方的关系:包括创建测试对象,设置测试的期待结果等等
- 调用:第二个A(ct)往往很简单,我们得调用需要测试的函数
- 断言:第三个A(ssert)最为关键,它描述了测试的目的和结果
方法
- TDD(测试驱动开发):先编写单元测试,然后编写代码让通过测试
- TDD 体现了 “以终为始” 的思想,即先制定目标,然后去验证是否实现了目标,而不是先做再去 “思考目标”
go test步骤
- 文件命名:
*_test.go
,测试函数func TestFuncName(t *testing.T)
查看结果
go test
:可以看到输出结果。go test -coverprofile=coverage.out
:输出一个coverage profile,该文件包含着测试的统计信息。-coverprofile
是统计信息保存的文件。
go tool cover -func=coverage.out
:查看测试结果。go test -cover
:可以查看覆盖率。- go tool cover -html=coverage.out:查看测试结果,打开浏览器查看覆盖报告。
go test -v -test.run FuncName
:测试一个函数。
包名
-
要提交修改go.mod。
-
包名一般有两种选择:
- pkgname:与被测包包名一致,可以直接引用被测包的任意函数,用在白盒测试
- pkgname_test:与被测包隔离,只能引用被测包的导出变量、函数等,用于黑盒测试
- 通常,应尽量使用黑盒测试。
- 白盒测试会与实现耦合,在以后代码重构时会引入额外的成本。
-
修改包名之后,记得要修改import。
测试用例
- 测试用例要尽可能地覆盖所有场景,而不是覆盖代码行。
- 场景覆盖地足够多,那么行覆盖率自然也会上去。
mock
- 你 mock 越多外部的接口,你测试的可靠性就越低。
stub
- gomonkey属于使用stub。
- 不提倡使用 gomonkey。
gomonkey
-
为函数打桩
-
ApplyFunc
-
target:函数名,不是string类型
-
conn := redigomock.NewConn() p := gomonkey.ApplyFunc(redigo.DialURL, func(rawurl string, options ...redigo.DialOption) (redigo.Conn, error){ return conn, nil }) defer p.Reset()
-
-
为成员方法打桩
- ApplyMethod
-
为全局变量打桩
-
为函数变量打桩
-
为函数打一个特定的桩序列
- ApplyFuncSeq
- Times:为测试次数
-
为成员方法打一个特定的桩序列
- ApplyMethodSeq
-
为函数变量打一个特定的桩序列