这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
测试关系着系统的质量,质量则决定着线上系统的稳定性,一旦出现bug漏洞,就会造成事故。
测试是避免事故的最后一道屏障。
测试一般分为:
- 回归测试是QA同学手动通过终端回归一些固定的主流程场景;
- 集成测试是对系统功能维度做测试验证;
- 单元测试是测试开发阶段,开发者对单独的函数、模块做功能验证。
层级从上至下,测试成本逐渐减低,而测试覆盖率逐步上升,所以单元测试覆盖率一定程度上决定这代码的质量。
单元测试
测试规则:
- 所有测试文件以_test.go结尾
- func TestXxx(*testing.T){} 函数模板
- 初始化逻辑放到TestMain中
代码覆盖率:
- 一般覆盖率:
50%~60%,较高覆盖率:80%+ - 测试分支相互独立、全面覆盖
- 测试单元粒度足够小,函数单一职责
Mock测试-解决测试中的依赖问题
工程中复杂的项目, -般会依赖****.* 而我们的单测需要保证稳定性和幂等性,稳定是指相互隔离,能在任何时间,任何环境,运行测试。幂等是指每一次测试运行都应该产生与之前一样的结果。而要实现这一目的就要用到mock机制。
func ReadFirstLine() string {
open, err := os.Open("log") // 打开一个文件
defer open.Close()
if err != nil {
return ""
}
scanner := bufio.NewScanner(open) // 对每行进行遍历
for scanner.Scan() {
return scanner.Text()
}
return ""
}
func ProcessFirstLine() string {
line := ReadFirstLine()
destLine := strings.ReplaceAll(line, "11", "00") // 替换11为00
return destLine
}
func TestProcessFirstLine(t *testing.T) { // 执行单元测试
firstLine := ProcessFirstLine()
assert.Equal(t, "line00", firstLine)
}
若文件进行了修改,测试就寄了
快速Mock函数:
- 为一个函数打桩
- 为一个方法打桩
- 具体函数为monkey:github.com/bouk/monkey
// 用函数A去替换函数B,B就是原函数,A就是打桩函数
func Patch(target, replacement interface{}) *PatchGuard {
// target就是原函数,replacement就是打桩函数
t := reflect.ValueOf(target)
r := reflect.ValueOf(replacement)
patchValue(t, r)
return &PatchGuard{t, r}
}
func Unpatch(target interface{}) bool {
// 保证了在测试结束之后需要把这个包卸载掉
return unpatchValue(reflect.ValueOf(target))
}
func TestProcessFirstLineWithMock(t *testing.T) {
monkey.Patch(ReadFirstLine, func() string {
return "line110"
})
defer monkey.Unpatch(ReadFirstLine)
line := ProcessFirstLine()
assert.Equal(t, "line000", line)
}
// 通过patch对ReadFirstLine进行打桩mock,默认返回line110,通过defer卸载mock
// 这样整个测试函数就摆脱了本地文件的束缚和依赖
基准测试
基准测试是指测试一段程序的性能及耗费CPU的程度;
在实际的项目开发中,经常会遇到代码性能瓶颈,为了定位问题,经常要对代码做性能分;
这时就用到了基准测试,其使用方法与单元测试类似。
- 优化代码,需要对当前代码分析
- 内置的测试框架提供了基准测试的能力