这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天 文章将介绍在项目开发过程中如何编写测试用例
测试类型
测试可分为回归测试、集成测试以及单元测试。
- 回归测试一般为用户亲自操作进行测试,例如手动鼠标点击或屏幕滑动
- 集成测试一般为专业测试人员使用编写的测试脚本进行自动化测试
- 单元测试需要开发人员在项目开发中进行重点编写
单元测试
- 编写单元测试文件应与需要被测试文件的同包以"_test"结尾
- 单元测试内的函数应以Test开始以被测试的函数名结尾,且被测试函数名首字母应大写
- 测试单元可为简单函数或模块函数
- 单元测试应保证分支独立、全面覆盖,测试单元密度足够小,函数单一职责
以下为一个add函数的测试单元
// my_test.go
func TestAdd(t *testing.T) {
ans := add(12, 34)
exp := 46
if ans != exp {
t.Error("答案错误")
}
}
使用assert可简化为
func TestAdd(t *testing.T) {
assert.Equal(t, 46,add(12, 34), "答案错误")
}
测试覆盖率
测试覆盖率可反映测试编写的是否全面,是用来度量测试完整性的一个手段,通过覆盖率可反映代码是否经过的足够的测试。其中一般代码覆盖率应达到50-60%,关键代码如支付应达到80%,计算方法可理解为经过测试的代码行数/总代码行数
// my.go
func add(a, b int) int {
return a + b
}
func bijiao(a, b int) int {
if a > b {
return 1
} else {
return -1
}
}
// my_test.go
func TestAdd(t *testing.T) {
assert.Equal(t, 122,add(6,6))
}
// 用于保证测试的全面
func TestBijiao1(t *testing.T) {
assert.Equal(t, -1, bijiao(12,34))
}
func TestBijiao2(t *testing.T) {
assert.Equal(t, 1, bijiao(62,34))
}
分析:bijiao函数内有一个if分支,若只对a>b进行测试则无法对bijiao函数测试全面,所以应对每一个分支都进行测试。类比到真实运行的系统,测试覆盖率较低则不能保证系统能够正常运行。
mock测试
mock测试目标是让用户在单元测试中低成本的完成打桩,mock通过"虚拟"代码替换掉依赖的方法和资源,减少对网络、文件或者数据库的依赖。
文章使用了monkey做mock测试,它在运行时通过汇编语言重写可执行文件,将目标函数或方法的实现跳转到桩实现,其原理类似于热补丁。
注意事项:
- monkey不支持内联函数,在测试的时候需要通过命令行参数
-gcflags=-l关闭Go语言的内联优化。 - monkey不是线程安全的,所以不能把它用到并发的单元测试中。
func readFile() string {
return readLine()
}
func readLine() string {
return "qwqwe1233"
}
防止内联优化执行 go test -run=TestFile -v -gcflags=-l
func TestFile(t *testing.T) {
monkey.Patch(readLine, func() string {
return "asda456"
})
defer monkey.Unpatch(readLine)
ss := readFile()
assert.Equal(t, "qwqwe1233", ss)
}
测试结果为 expected: "qwqwe1233" actual : "asda456"
基准测试
基准测试就是在一定的工作负载之下检测程序性能的一种方法
- 基准测试以Benchmark开始,通过-bench=.标记来执行该包下的所有的基准函数
- 参数类型为b *testing.B
- 基准测试必须要执行b.N次
- 使用for进行串行执行
- 使用b.RunParallel进行并行执行
// my.go
var index [10]int
func initIndex() {
for i := 0; i < 10; i++ {
index[i] = i
}
}
func selectIndex() int {
return index[rand.Intn(10)]
}
// my_test.go
func BenchmarkSelect1(b *testing.B) {
initIndex()
b.ResetTimer()
for i := 0; i < b.N; i++ {
selectIndex()
}
}
func BenchmarkSelect2(b *testing.B) {
initIndex()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
selectIndex()
}
})
}
测试结果:
文章引用的开源包
参考文章