go 语言 测试覆盖率

覆盖率

语句的覆盖率是指在测试中至少被运行一次的代码占总代码数的比例。

生成测试报告

在生成报告之前,要确保所有的测试都正常通过。使用go test命令配合不同的参数标示可以生成不同类型的覆盖率分析报告

使用标志coverprofile

go test gott/prime -coverprofile=c.out
ok      gott/prime      0.013s  coverage: 93.8% of statements

在运行每个测试前,会把参与测试的源代码拷贝一份,并对每个词法块插入一个布尔变量,来统计代码块在测试中是否被执行过,以此来统计代码覆盖率,统计日志数据写入c.out文件

go 语言 测试覆盖率

使用标志covermode

如果同时使用了-covermode=count,会在每个代码块插入计数器以统计代码块被执行的次数,用这个功能可以看到哪些代码是频繁执行的热点代码

go test gott/prime -coverprofile=c.out -covermode=count
ok      gott/prime      0.015s  coverage: 93.8% of statements

go 语言 测试覆盖率

查看测试报告

go tool cover -html=c.out

运行后会自动在浏览器中打开,绿色的代码块代表被测试覆盖到了,红色的则表示没有被覆盖到。如果使用了 -covermode=count标志,会用红、灰、绿 三种颜色表示代码被调用的频率,红色表示没有调用,灰色表示频率较低,绿色随颜色深浅表示不同程度的频率调用。具体可见上图测试报告。

源文件

// primes_test.go
func TestPrimes(t *testing.T) {
	max := 1000
	primes := GetPrimes(max)
	t.Log(primes)
}

// primes.go
// 查找质数
func GetPrimes(max int) []int {
	if max <= 1 {
		return []int{}
	}
	marks := make([]bool, max)
	var count int
	squareRoot := int(math.Sqrt(float64(max)))
	for i := 2; i <= squareRoot; i++ {
		if !marks[i] {
			for j := i * i; j < max; j += i {
				if !marks[j] {
					marks[j] = true
					count++
				}
			}
		}
	}
	primes := make([]int, 0, max-count)
	for i := 2; i < max; i++ {
		if !marks[i] {
			primes = append(primes, i)
		}
	}
	return primes
}

小结

  • 测试不可能是完整的,计算机科学家Edsger Dijkstra曾说过:“测试能证明缺陷存在,而无法证明没有缺陷。”
  • 实现100%的测试覆盖率听起来很美,但是在具体实践中通常是不可行的,也不是值得推荐的做法。应该对更需要测试的地方添加测试代码,而不是一味的为每个方法都加入测试代码
  • 测试覆盖率工具可以帮助我们快速识别测试薄弱的地方