【3】测试 | 青训营笔记

108 阅读2分钟

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

测试分类

单元测试:开发阶段,开发者对单独的函数、模块做功能验证。

集成测试:对系统功能维度做测试验证。

回归测试:回归一些固定的主流程场景。

单元测试,覆盖率最大,成本最低,所以一定程度上决定着代码的质量。

单元测试

规则

测试文件以_test.go结尾。

测试函数 func TestXx(t *testing.T)。

初始化逻辑放到TestMain中。

func TestMain(m *testing.M){
	//数据装载 配置初始化
	code:=m.Run() //运行package下所有单测
	//释放资源
	os.Exit(code)
}

例子

func TestHelloTom(t *testing.T) {
	output := HelloTom()
	expectOutput := "Tom"
	if output != expectOutput {
		t.Errorf("Expected %s do not match actual %s", expectOutput, output)
	}
}

go test执行测试。

assert

可以使用一些assert包进行比较。

import "github.com/stretchr/testify/assert"

assert.Equal(t, expectOutput, output)

覆盖率

go test a_test.go a.go -cover计算覆盖率。

计算测试执行过的代码行数占代码总行数的比例。

Tips

一般覆盖率50%~60%,资金型服务较高覆盖率80%+。

测试分支相互独立、全面覆盖。

测试单元粒度足够小,函数单一职责。

Mock测试

复杂的工程项目会有很多外部依赖,而单元测试需要保证幂等性和稳定性。

幂等性,是指测试每次运行都能产生相同的结果。

稳定性,是指测试能相互隔离,能在任何时间任何环境运行。

func TestProcessFirstLineWithMock(t *testing.T) {
	monkey.Patch(ReadFirstLine, func() string {
		return "line110"
	})
	defer monkey.Unpatch(ReadFirstLine)
	line := ProcessFirstLine()
	assert.Equal(t, "line000", line)
}

monkey是一个开源的mock测试库。

替换读取文件的函数,使测试不依赖本地文件。

用打桩函数替换原函数,原理是在运行时替换内存中函数的地址。

基准测试

基准测试,是指测试程序的运行性能、CPU消耗等。

开发中经常会遇到性能瓶颈,为了定位问题需要做性能分析,因此要用到基准测试。

例子

func BenchmarkSelect(b *testing.B) {
	InitServerIndex()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		Select()
	}
}

N值反复递增循环测试。

准备操作不应该作为基准测试的范围,使用ResetTimer函数重置计时器。

func BenchmarkSelectParallel(b *testing.B) {
	InitServerIndex()
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			Select()
		}
	})
}

多协程并发测试。

go test -bench="."执行基准测试。

优化

发现代码在并发情况下存在劣化,主要原因是rand为了保证全局的随机性和并发安全,持有了一把全局锁。

使用公司开源的fastrand,牺牲了一定的数列一致性,能够大幅度提升性能。