我们每开发一个功能,都应该对其进行测试,以确保代码的正确性,而 go 语言为我们提供了一系列的工具来完成测试,其中就包括单元测试
什么是单元测试
顾名思义,单元测试强调的是对单元进行测试。在开发中,一个单元可以是一个函数、一个模块等。一般情况下,你要测试的单元应该是一个完整的最小单元,比如 Go 语言的函数。这样的话,当每个最小单元都被验证通过,那么整个模块、甚至整个程序就都可以被验证通过。
单元测试应该由开发人员编写。
怎么使用 go 语言的单元测试
接下来我以一个简单的例子来演示 go 语言单元测试的使用。
我们先编写一个简单的函数,这个函数的功能是求一个数的阶乘。
func Factorial(n int) int {
// 负数没有阶乘,我们这里直接返回
if n < 0 {
return 0
}
// 0的阶乘为1
if n == 0 {
return 1
}
// 循环求阶乘
fac := 1
for i := 2; i <= n; i++ {
fac *= i
}
return fac
}
这个函数编写好后我们编写一个测试函数,目的是测试阶乘函数是否正确。
测试函数与被测试函数放在同一目录下,文件名为 _test.go ,必须这么写,其中 * 是被测试文件的文件名。函数名一般为为 Test ,*为被测试函数的函数名。
func TestFactorial(t *testing.T) {
// 这里先初始化一个 map 存一些已知的结果用于与函数的结果比较
m := make(map[int]int, 10)
m[0] = 1
m[1] = 1
m[2] = 2
m[3] = 6
m[4] = 24
m[5] = 120
m[6] = 720
m[7] = 5040
m[8] = 40320
m[9] = 362880
for i := 0; i < 10; i++ {
fmt.Println(m[i] == Factorial(i))
}
}
然后即可运行如下命令,进行单元测试:
go test -v .
输出如下结果
=== RUN TestFactorial
true
true
true
true
true
true
true
true
true
true
--- PASS: TestFactorial (0.00s)
PASS
ok context_demo 0.001s
在打印的测试结果中,你可以看到 PASS 标记,说明单元测试通过,true 为我们在代码中打印的结果。
这就是一个完整的 Go 语言单元测试用例,它是在 Go 语言提供的测试框架下完成的。Go 语言测试框架可以让我们很容易地进行单元测试,但是需要遵循五点规则。
- 含有单元测试代码的 go 文件必须以 _test.go 结尾,Go 语言测试工具只认符合这个规则的文件。
- 单元测试文件名 _test.go 前面的部分最好是被测试的函数所在的 go 文件的文件名,比如以上示例中单元测试文件叫 main_test.go,因为测试的 Factorial 函数在 main.go 文件里。
- 单元测试的函数名必须以 Test 开头,是可导出的、公开的函数。
- 测试函数的签名必须接收一个指向 testing.T 类型的指针,并且不能返回任何值。
- 函数名最好是 Test + 要测试的函数名,比如例子中是 TestFactorial,表示测试的是 Factorial 这个函数。
遵循以上规则,你就可以很容易地编写单元测试了。单元测试的重点在于熟悉业务代码的逻辑、场景等,以便尽可能地全面测试,保障代码质量。
单元测试覆盖率
以上 Factorial 函数是否全部被执行了呢?这就引出了单元测试覆盖率的概念。
go 语言也为我们提供了非常方便的工具来查看,我们只需要在命令中指定--coverprofile即可
go test --coverprofile=test.cover .
输出
ok context_demo 0.001s coverage: 87.5% of statements
其中87.5%便是单元测试覆盖率,执行完此命令后同时还会在当前目录下生成一个名为test.cover的文件,就是我们指定的--coverprofile的参数。
上面的单元测试覆盖率不是百分之百,这代表函数有一部分是没有执行到的,想要获得更详细的信息,我们可以使用以下命令查看。
go tool cover -html=test.cover -o=test.html
其中-html=test.cover表示我们想要基于test.cover生成一个 HTML 文件,-o是指定生成文件的文件名,然后我们使用游览器打开 HTML 文件。
其中红色的便是没有覆盖到的代码区域。
总结
- 单元测试是是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。
- 单元测试是非常重要的,对于未测试的代码,如果强行合并到代码库,可能影响其他人的开发;如果强行上线,可能导致线上 Bug、影响用户使用。
- go 语言为我们提供了
go test命令来帮助我们快速进行单元测试,我们还可以配合go tool命令来获得更精确的报告,在终端输入go help test获取更多有关go test命令的信息。