go test - 测试工具
go test 是 Go 官方提供的测试工具,用于运行单元测试、基准测试和示例代码。
📋 概述
难度级别:⭐⭐⭐
考察范围:测试/代码质量
技术标签:单元测试 基准测试 测试覆盖率
问题分析
go test 是 Go 开发中最重要的测试工具,掌握其用法对于编写高质量代码至关重要。
🎯 核心功能
1. 基本用法
bash
# 运行当前包的所有测试
go test
# 运行指定包的测试
go test ./pkg/...
# 运行所有包的测试
go test ./...
# 运行特定测试函数
go test -run TestFunctionName
# 详细输出
go test -v
# 显示覆盖率
go test -cover2. 测试文件命名
测试文件必须以 _test.go 结尾:
project/
├── main.go
├── main_test.go # 测试文件
├── utils.go
└── utils_test.go # 测试文件📝 详细示例
示例 1:单元测试
go
package utils
func Add(a, b int) int {
return a + b
}
func Multiply(a, b int) int {
return a * b
}go
package utils
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2, 3) = %d; want 5", result)
}
}
func TestMultiply(t *testing.T) {
result := Multiply(2, 3)
if result != 6 {
t.Errorf("Multiply(2, 3) = %d; want 6", result)
}
}运行测试:
bash
$ go test -v
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
=== RUN TestMultiply
--- PASS: TestMultiply (0.00s)
PASS
ok example/utils 0.001s示例 2:表驱动测试
go
package utils
import "testing"
func TestAdd(t *testing.T) {
tests := []struct {
name string
a int
b int
expected int
}{
{"positive", 2, 3, 5},
{"negative", -2, -3, -5},
{"zero", 0, 0, 0},
{"mixed", -2, 3, 1},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d",
tt.a, tt.b, result, tt.expected)
}
})
}
}示例 3:基准测试
go
package utils
import "testing"
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}
func BenchmarkMultiply(b *testing.B) {
for i := 0; i < b.N; i++ {
Multiply(2, 3)
}
}运行基准测试:
bash
$ go test -bench=.
goos: darwin
goarch: amd64
BenchmarkAdd-8 1000000000 0.313 ns/op
BenchmarkMultiply-8 1000000000 0.313 ns/op
PASS示例 4:测试覆盖率
bash
# 显示覆盖率
go test -cover
# 生成覆盖率文件
go test -coverprofile=coverage.out
# 查看详细覆盖率
go tool cover -html=coverage.out🔧 高级用法
1. 测试标志
bash
# 运行特定测试
go test -run TestAdd
# 运行匹配模式的测试
go test -run TestAdd|TestMultiply
# 并行运行测试
go test -parallel 4
# 超时设置
go test -timeout 30s
# 显示详细输出
go test -v
# 显示测试后的覆盖率
go test -cover
# 生成覆盖率文件
go test -coverprofile=coverage.out
# 跳过缓存
go test -count=12. 基准测试标志
bash
# 运行基准测试
go test -bench=.
# 运行特定基准测试
go test -bench=BenchmarkAdd
# 显示内存分配
go test -bench=. -benchmem
# 设置运行时间
go test -bench=. -benchtime=10s
# 设置运行次数
go test -bench=. -count=53. 测试辅助函数
go
package utils
import (
"testing"
"reflect"
)
func TestHelper(t *testing.T) {
// t.Helper() 标记为辅助函数
// 错误信息会指向调用者,而不是辅助函数
helper(t, "test")
}
func helper(t *testing.T, msg string) {
t.Helper()
if msg == "" {
t.Error("msg is empty")
}
}4. 测试清理
go
package utils
import "testing"
func TestWithCleanup(t *testing.T) {
// 设置清理函数
t.Cleanup(func() {
// 清理资源
cleanup()
})
// 测试代码
doSomething()
}🎯 最佳实践
1. 测试组织
go
// 使用子测试组织相关测试
func TestAdd(t *testing.T) {
t.Run("positive", func(t *testing.T) {
// 测试正数
})
t.Run("negative", func(t *testing.T) {
// 测试负数
})
}2. 测试数据
go
// 使用表驱动测试
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
// 测试用例
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 测试逻辑
})
}
}3. Mock 和 Stub
go
// 使用接口实现 Mock
type DB interface {
Get(id int) (string, error)
}
type mockDB struct{}
func (m *mockDB) Get(id int) (string, error) {
return "mock", nil
}
func TestWithMock(t *testing.T) {
db := &mockDB{}
// 使用 mock
}📊 测试覆盖率
查看覆盖率
bash
# 基本覆盖率
go test -cover
# 详细覆盖率报告
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
# 函数级别覆盖率
go test -coverprofile=coverage.out -covermode=atomic
go tool cover -func=coverage.out覆盖率目标
- 最低要求:60%
- 良好:80%
- 优秀:90%+
🔍 常见问题
Q1: 如何跳过某些测试?
go
// 使用 build tag
// +build integration
package utils
import "testing"
func TestIntegration(t *testing.T) {
// 集成测试
}bash
# 运行集成测试
go test -tags=integrationQ2: 如何测试私有函数?
go
// 方式1:通过公共函数测试
func TestPublic(t *testing.T) {
// 间接测试私有函数
}
// 方式2:将函数移到测试文件(不推荐)
// 在 _test.go 文件中可以访问同包的私有函数Q3: 如何测试并发代码?
go
func TestConcurrent(t *testing.T) {
// 使用 race detector
// go test -race
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// 测试代码
}()
}
wg.Wait()
}