📌 一、Go 的测试框架介绍
Go 内置了强大的测试框架,不需要第三方库,只需引入:
所有测试文件必须以 _test.go
结尾,所有测试函数以 Test
开头,并接受 *testing.T
参数。
📘 二、单元测试(Unit Test)
✅ 基本格式
1 2 3 4 5 6
| func TestAdd(t *testing.T) { result := Add(2, 3) if result != 5 { t.Errorf("Expected 5, got %d", result) } }
|
📁 文件结构示例
1 2 3
| calc/ ├── calc.go └── calc_test.go
|
📌 示例代码
1 2 3 4 5 6
| package calc
func Add(a, b int) int { return a + b }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| package calc
import "testing"
func TestAdd(t *testing.T) { got := Add(1, 2) want := 3
if got != want { t.Errorf("Add(1, 2) = %d; want %d", got, want) } }
|
🚀 运行测试
🧪 三、表驱动测试(推荐)
适合多个输入输出的函数测试,易扩展、代码更清晰。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func TestAddTableDriven(t *testing.T) { cases := []struct{ a, b, expected int }{ {1, 2, 3}, {2, 2, 4}, {10, 5, 15}, }
for _, c := range cases { got := Add(c.a, c.b) if got != c.expected { t.Errorf("Add(%d, %d) = %d; want %d", c.a, c.b, got, c.expected) } } }
|
🕓 四、基准测试(Benchmark)
用于性能评估。函数名以 Benchmark
开头,接收 *testing.B
参数。
1 2 3 4 5
| func BenchmarkAdd(b *testing.B) { for i := 0; i < b.N; i++ { Add(10, 20) } }
|
执行命令:
🧪 五、测试覆盖率
查看测试覆盖率:
生成详细报告:
1 2
| go test -coverprofile=cover.out go tool cover -html=cover.out
|
🧰 六、实际开发中的测试最佳实践
做法 |
描述 |
✅ 使用表驱动测试 |
可读性强、维护方便 |
✅ 测试覆盖边界条件 |
不仅测常规输入,还要测试错误输入、零值等 |
✅ 使用子测试 |
t.Run("case name", func(t *testing.T) {...}) 有助于分组管理测试 |
✅ 保持测试快速 |
测试应能快速运行,不阻塞开发 |
✅ 对接口进行测试 |
方便 mock 和替换 |
✅ 使用 go test -race |
检查并发代码中的数据竞争问题 |
🧪 七、测试中的 Mock 与 Stub(进阶)
Go 没有内置 mock 框架,但可以手动定义接口并注入假实现。
1 2 3 4 5 6 7 8 9
| type DB interface { GetUser(id int) string }
type MockDB struct{}
func (m *MockDB) GetUser(id int) string { return "mock-user" }
|
测试中使用:
1 2 3 4 5 6 7
| func TestService(t *testing.T) { service := NewService(&MockDB{}) user := service.GetUserName(1) if user != "mock-user" { t.Fail() } }
|
✅ 总结
类型 |
用法 |
单元测试 |
测试函数是否输出正确结果 |
表驱动测试 |
测试多个输入组合 |
基准测试 |
测试性能 |
子测试 |
多维度组织测试 |
覆盖率 |
检查测试是否全面 |
Mock 接口 |
模拟依赖 |