这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
Part1 单元测试
单元测试(Unit Tests, UT) 是一个优秀项目不可或缺的一部分,特别是在一些频繁变动和多人合作开发的项目中尤为重要。
- 你或多或少都会有因为自己的提交,导致应用挂掉或服务宕机的经历。如果这个时候你的修改导致测试用例失败,你再重新审视自己的修改,发现之前的修改还有一些特殊场景没有包含,恭喜你减少了一次上库失误。 -- 减少出错
- 项目很大,启动环境很复杂,你优化了一个函数的性能,或是添加了某个新的特性,如果部署在正式环境上之后再进行测试,成本太高。对于这种场景,几个小小的测试用例或许就能够覆盖大部分的测试场景。 -- 降低成本
- 而且在开发过程中,效率最高的莫过于所见即所得了,单元测试也能够帮助你做到这一点,试想一下,假如你一口气写完一千行代码,debug 的过程也不会轻松,如果在这个过程中,对于一些逻辑较为复杂的函数,同时添加一些测试用例,即时确保正确性,最后集成的时候,会是另外一番体验。 -- 增加上线自信
接下来将介绍如何使用 Go 语言的标准库 testing 进行单元测试。
1. 文件命名:
Go 语言推荐测试文件和源代码文件放在一块,测试文件以 `_test.go` 结尾。如图:为了测试`PassLine.go`中的某一个函数我们应该在同等的目录下 新建测试文件 `PassLine_test.go` 这样非常有利于我们观察和处理文件
2.函数命名以及测试函数的命名规则:
我们在代码文件中 有函数命名为`PassLine(x int)bool`
- 测试用例名称一般命名为
Test加上待测试的方法名。 - 测试用的参数有且只有一个,在这里是
t *testing.T。 - 基准测试(benchmark)的参数是
*testing.B,TestMain 的参数是*testing.M类型。
3.测试启动的方法
运行
go test 测试运行
go test -v参数会显示每个用例的测试结果
go test -v -cover 可以查看覆盖率。
如果只想运行其中的一个用例,例如 `TestAdd`,可以用 `-run` 参数指定,该参数支持通配符 `*`,和部分正则表达式,例如 `^`、`$`。
Part2 Mock测试
mock/stub 测试,当待测试的函数/对象的依赖关系很复杂,并且有些依赖不能直接创建,例如数据库连接、文件I/O等。这种场景就非常适合使用 mock/stub 测试。简单来说,就是用 mock 对象模拟依赖项的行为
简单来说当我们的测试对一些文件,数据库之类的产生了强依赖 那么我们的文件修改了 测试也就自然失效了
https://github.com/bouk/monkey下载一个mock
mock实现的原理就是篡改函数调用的指针 当我们调用目标函数的时候会重定向指向我们指定的新函数 从而屏蔽掉文件的影响去对上层进行验证
monkey.Patch(xx原函数 , xx目标函数)替换 monkey.Unpatch(xx 原函数) 恢复
Part3 基准测试
基准测试用例的定义如下:
func BenchmarkXxx(b *testing.B){
// ...
}
- 函数名必须以
Benchmark开头,后面一般跟待测试的函数名 - 参数为
b *testing.B。 - 执行基准测试时,需要添加
-bench参数。 -benchmem参数可以度量内存分配的次数。- $ go test -benchmem -bench .运行语句
例如:
func BenchmarkHello(b *testing.B) {
for i := 0; i < b.N; i++ {
XXX测试函数
}
}
如果在运行前基准测试需要一些耗时的配置,则可以使用 b.ResetTimer() 先重置定时器以达到局部测试时间
func BenchmarkXXX(b *testing.B) {
... // 耗时操作
b.ResetTimer()
for i := 0; i < b.N; i++ {
xxx测试函数
}
}
使用 RunParallel 测试并发性能
func BenchmarkXXXParallel(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// 所有 goroutine 一起,循环一共执行 b.N 次
xxx测试函数
}
})
}
参考材料: [极客兔兔]
码风略丑 读者见谅 --2023/1/16