Go 语言测试(go test)使用说明
Go 语言内置了强大的测试框架,通过 go test 命令可以方便地进行单元测试、基准测试和示例测试。
基本概念
- 测试文件以
_test.go结尾 - 测试函数以
Test开头,参数为*testing.T - 基准测试函数以
Benchmark开头,参数为*testing.B - 示例函数以
Example开头,无参数
常用命令
1go test # 运行当前目录下的所有测试
2go test -v # 显示详细输出
3go test -run TestName # 运行指定的测试函数
4go test ./... # 递归测试所有子目录
5go test -cover # 显示测试覆盖率
6go test -bench . # 运行基准测试
7go test -timeout 30s # 设置测试超时时间
完整示例
下面提供一个包含单元测试、表格驱动测试、基准测试和示例测试的完整案例:
calculator.go
1package calculator
2
3import (
4 "errors"
5 "math"
6)
7
8// Add 加法运算
9func Add(a, b int) int {
10 return a + b
11}
12
13// Subtract 减法运算
14func Subtract(a, b int) int {
15 return a - b
16}
17
18// Multiply 乘法运算
19func Multiply(a, b int) int {
20 return a * b
21}
22
23// Divide 除法运算
24func Divide(a, b float64) (float64, error) {
25 if b == 0 {
26 return 0, errors.New("division by zero")
27 }
28 return a / b, nil
29}
30
31// IsPrime 判断是否为质数
32func IsPrime(n int) bool {
33 if n <= 1 {
34 return false
35 }
36 if n <= 3 {
37 return true
38 }
39 if n%2 == 0 || n%3 == 0 {
40 return false
41 }
42 for i := 5; i*i <= n; i += 6 {
43 if n%i == 0 || n%(i+2) == 0 {
44 return false
45 }
46 }
47 return true
48}
49
50// Factorial 计算阶乘
51func Factorial(n int) int {
52 if n < 0 {
53 return -1
54 }
55 if n == 0 {
56 return 1
57 }
58 result := 1
59 for i := 1; i <= n; i++ {
60 result *= i
61 }
62 return result
63}
64
65// Sqrt 计算平方根
66func Sqrt(x float64) (float64, error) {
67 if x < 0 {
68 return 0, errors.New("negative number")
69 }
70 return math.Sqrt(x), nil
71}
72
calculator_test.go
1package calculator
2
3import (
4 "fmt"
5 "testing"
6)
7
8// TestAdd 基本的单元测试
9func TestAdd(t *testing.T) {
10 result := Add(2, 3)
11 expected := 5
12 if result != expected {
13 t.Errorf("Add(2, 3) = %d; want %d", result, expected)
14 }
15}
16
17// TestSubtract 使用子测试
18func TestSubtract(t *testing.T) {
19 t.Run("positive numbers", func(t *testing.T) {
20 result := Subtract(10, 5)
21 if result != 5 {
22 t.Errorf("got %d, want 5", result)
23 }
24 })
25
26 t.Run("negative result", func(t *testing.T) {
27 result := Subtract(5, 10)
28 if result != -5 {
29 t.Errorf("got %d, want -5", result)
30 }
31 })
32}
33
34// TestDivide 测试带错误返回的函数
35func TestDivide(t *testing.T) {
36 // 正常情况
37 result, err := Divide(10, 2)
38 if err != nil {
39 t.Fatalf("unexpected error: %v", err)
40 }
41 if result != 5.0 {
42 t.Errorf("Divide(10, 2) = %f; want 5.0", result)
43 }
44
45 // 除零错误
46 _, err = Divide(10, 0)
47 if err == nil {
48 t.Error("expected error for division by zero, got nil")
49 }
50}
51
52// TestIsPrime 表格驱动测试(推荐方式)
53func TestIsPrime(t *testing.T) {
54 testCases := []struct {
55 name string
56 input int
57 expected bool
58 }{
59 {"prime 2", 2, true},
60 {"prime 3", 3, true},
61 {"prime 5", 5, true},
62 {"prime 7", 7, true},
63 {"prime 11", 11, true},
64 {"not prime 1", 1, false},
65 {"not prime 4", 4, false},
66 {"not prime 6", 6, false},
67 {"not prime 8", 8, false},
68 {"not prime 9", 9, false},
69 {"negative", -5, false},
70 }
71
72 for _, tc := range testCases {
73 t.Run(tc.name, func(t *testing.T) {
74 result := IsPrime(tc.input)
75 if result != tc.expected {
76 t.Errorf("IsPrime(%d) = %v; want %v", tc.input, result, tc.expected)
77 }
78 })
79 }
80}
81
82// TestFactorial 表格驱动测试
83func TestFactorial(t *testing.T) {
84 tests := []struct {
85 input int
86 expected int
87 }{
88 {0, 1},
89 {1, 1},
90 {5, 120},
91 {10, 3628800},
92 {-1, -1}, // 错误情况
93 }
94
95 for _, tt := range tests {
96 t.Run(fmt.Sprintf("factorial_%d", tt.input), func(t *testing.T) {
97 result := Factorial(tt.input)
98 if result != tt.expected {
99 t.Errorf("Factorial(%d) = %d; want %d", tt.input, result, tt.expected)
100 }
101 })
102 }
103}
104
105// TestSqrt 测试浮点数
106func TestSqrt(t *testing.T) {
107 result, err := Sqrt(16)
108 if err != nil {
109 t.Fatalf("unexpected error: %v", err)
110 }
111 if result != 4.0 {
112 t.Errorf("Sqrt(16) = %f; want 4.0", result)
113 }
114
115 // 测试负数
116 _, err = Sqrt(-1)
117 if err == nil {
118 t.Error("expected error for negative input")
119 }
120}
121
122// BenchmarkAdd 基准测试
123func BenchmarkAdd(b *testing.B) {
124 for i := 0; i < b.N; i++ {
125 Add(100, 200)
126 }
127}
128
129// BenchmarkIsPrime 基准测试
130func BenchmarkIsPrime(b *testing.B) {
131 for i := 0; i < b.N; i++ {
132 IsPrime(97)
133 }
134}
135
136// BenchmarkFactorial 基准测试
137func BenchmarkFactorial(b *testing.B) {
138 for i := 0; i < b.N; i++ {
139 Factorial(10)
140 }
141}
142
143// ExampleAdd 示例函数
144func ExampleAdd() {
145 result := Add(2, 3)
146 fmt.Println(result)
147 // Output: 5
148}
149
150// ExampleDivide 示例函数
151func ExampleDivide() {
152 result, _ := Divide(10, 2)
153 fmt.Println(result)
154 // Output: 5
155}
156
157// ExampleIsPrime 示例函数
158func ExampleIsPrime() {
159 fmt.Println(IsPrime(7))
160 fmt.Println(IsPrime(8))
161 // Output:
162 // true
163 // false
164}
165
166// TestMain 测试主函数(可选)
167// 可以在所有测试前后执行设置和清理工作
168func TestMain(m *testing.M) {
169 // 测试前的设置
170 fmt.Println("Setting up tests...")
171
172 // 运行测试
173 code := m.Run()
174
175 // 测试后的清理
176 fmt.Println("Cleaning up after tests...")
177
178 // 退出
179 // os.Exit(code)
180 _ = code
181}
182
运行测试的命令示例
1# 基本测试
2go test
3
4# 详细输出
5go test -v
6
7# 运行特定测试
8go test -run TestAdd
9go test -run TestIsPrime
10
11# 运行包含特定名称的测试
12go test -run Prime
13
14# 测试覆盖率
15go test -cover
16go test -coverprofile=coverage.out
17go tool cover -html=coverage.out # 生成HTML覆盖率报告
18
19# 运行基准测试
20go test -bench .
21go test -bench BenchmarkAdd
22go test -benchmem # 显示内存分配统计
23
24# 并行测试
25go test -parallel 4
26
27# 设置超时
28go test -timeout 10s
测试最佳实践
- 使用表格驱动测试:可以用更少的代码测试更多场景
- 使用子测试:通过
t.Run()组织相关测试 - 测试错误情况:不仅测试正常流程,也要测试异常情况
- 使用有意义的测试名称:便于识别失败的测试
- 避免测试间依赖:每个测试应该独立运行
- 使用
t.Helper():标记辅助函数,使错误报告更准确 - 合理使用 Mock:对于复杂依赖,使用接口和 Mock 简化测试
这些示例涵盖了 Go 测试的主要用法,可以根据实际需求进行调整和扩展。