1. 测试文件的组织
在 Go 中,测试文件通常与被测试的源文件位于同一包内,并遵循以下命名规范:
- 源文件 :
xxx.go
- 测试文件 :
xxx_test.go
测试文件的命名必须以 _test.go
结尾,这样 Go 工具链才能识别并将其作为测试文件处理。
2. 测试函数的签名
测试函数必须满足以下签名:
go
func TestXxx(t *testing.T) { ... }
- 函数名以
Test
开头,后面跟被测试的函数或功能名称(通常首字母大写)。 - 接受一个参数
*testing.T
,用于报告测试失败和日志信息。
二、编写测试函数
1. 基本示例
假设有一个简单的加法函数 Add
,位于 math.go
文件中:
go
// math.go
package mathutil
func Add(a, b int) int {
return a + b
}
对应的测试文件 math_test.go
可以这样编写:
go
// math_test.go
package mathutil
import (
"testing"
)
func TestAdd(t *testing.T) {
tests := []struct {
a, b, expected int
}{
{1, 2, 3},
{0, 0, 0},
{-1, 1, 0},
}
for _, tt := range tests {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
}
}
}
2. 使用子测试
Go 1.7 引入了子测试(subtests),使得在同一个测试函数中运行多个相关测试更加方便:
go
func TestAdd(t *testing.T) {
tests := []struct {
a, b, expected int
}{
{1, 2, 3},
{0, 0, 0},
{-1, 1, 0},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
}
})
}
}
3. 使用表驱动测试
表驱动测试是一种常见的测试模式,通过定义一组输入和预期输出来测试函数的行为:
go
func TestMultiply(t *testing.T) {
tests := []struct {
a, b, expected int
}{
{2, 3, 6},
{0, 5, 0},
{-2, 4, -8},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%d*%d", tt.a, tt.b), func(t *testing.T) {
result := Multiply(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Multiply(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
}
})
}
}
三、运行测试
1. 使用 go test
命令
在包含测试文件的包目录下,运行以下命令即可执行所有测试:
bash
go test
2. 运行特定测试
要运行特定的测试函数,可以使用 -run
参数,支持正则表达式:
arduino
go test -run TestAdd
3. 查看详细输出
使用 -v
标志可以查看每个测试函数的详细输出:
bash
go test -v
4. 并行运行测试
使用 t.Parallel()
可以让测试函数并行执行,提高测试效率:
scss
func TestSomething(t *testing.T) {
t.Parallel()
// 测试代码
}
运行测试时,可以使用 -parallel
指定并行执行的测试数量:
bash
go test -parallel 4
5.测试覆盖率:
-
使用
go test -cover
查看测试覆盖率。 -
生成覆盖率文件:
inigo test -coverprofile=coverage.out go tool cover -html=coverage.out
示例:完整的测试流程
以下是一个综合示例,展示如何编写、运行和检查测试覆盖率。
1. 源代码
go
// mathutil/math.go
package mathutil
func Add(a, b int) int {
return a + b
}
func Multiply(a, b int) int {
return a * b
}
2. 测试代码
go
// mathutil/math_test.go
package mathutil
import (
"testing"
)
func TestAdd(t *testing.T) {
tests := []struct {
a, b, expected int
}{
{1, 2, 3},
{0, 0, 0},
{-1, 1, 0},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
}
})
}
}
3. 运行测试和覆盖率
ini
go test -v -coverprofile=coverage.out
go tool cover -html=coverage.out
Go 提供了强大而简洁的测试工具,使得编写和维护测试变得非常方便。通过合理组织测试文件、编写可测试的代码、以及定期检查测试覆盖率,开发者可以确保代码的质量和可靠性。结合持续集成流程,自动化测试更是保障项目稳定性的重要手段。