GO 语言单元测试入门

6 阅读2分钟

Go 的测试工具链高度集成、零依赖。 testing 是标准库,go test 是官方命令 —— 开箱即用。


一、基本规范

规范说明
测试文件_test.go 结尾,通常与被测代码同包
测试函数func TestXxx(t *testing.T)
运行go test / go test -v
// calc.go
func Add(a, b int) int { return a + b }

// calc_test.go
func TestAdd(t *testing.T) {
    result := Add(2, 3)
    if result != 5 {
        t.Errorf("got %d, want 5", result)
    }
}

二、错误报告

方法行为适用
t.Error/t.Errorf记录错误,继续执行多个断言需全部检查
t.Fatal/t.Fatalf记录错误 + 立即终止前置条件失败
func TestParse(t *testing.T) {
    u, err := url.Parse("http://example.com")
    if err != nil {
        t.Fatalf("setup failed: %v", err) // 不可恢复
    }
    if u.Scheme != "http" {
        t.Errorf("scheme = %q, want http", u.Scheme) // 继续检查
    }
}

三、表驱动测试(Table-Driven)

Go 推荐的测试模式:

func TestAdd(t *testing.T) {
    tests := []struct {
        name string
        a, b, want int
    }{
        {"positive", 2, 3, 5},
        {"negative", -1, -1, -2},
        {"zero", 0, 0, 0},
    }

    for _, tt := range tests {
        tt := tt  // 捕获循环变量
        t.Run(tt.name, func(t *testing.T) {
            if got := Add(tt.a, tt.b); got != tt.want {
                t.Errorf("Add(%d,%d) = %d; want %d", tt.a, tt.b, got, tt.want)
            }
        })
    }
}

每个子测试可独立运行:go test -run TestAdd/positive


四、t.Cleanup(Go 1.14+)

替代 defer 的特性:无论测试成功/失败/panic,均保证执行。

func TestWithDB(t *testing.T) {
    db := setupDB(t)
    t.Cleanup(func() { db.Close() })  // 总是执行
    // ...
}

五、Benchmark 测试

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {  // b.N 由框架自动调整
        Add(2, 3)
    }
}
go test -bench=. -benchmem

六、Mock:接口抽象 + 依赖注入

Go 不依赖 heavy mock 框架,通过接口抽象实现解耦:

type HTTPClient interface {
    Get(url string) (*http.Response, error)
}

// 测试时传入 mock
type mockClient struct{ resp *http.Response; err error }
func (m *mockClient) Get(_ string) (*http.Response, error) { return m.resp, m.err }

原则:Mock 接口,而非结构体;测试行为,而非实现。


七、测试辅助函数

标记 t.Helper() 让错误定位指向调用处:

func assertEq(t *testing.T, got, want int) {
    t.Helper()  // ← 关键
    if got != want {
        t.Fatalf("got %d, want %d", got, want)
    }
}

八、常用命令

命令说明
go test运行当前包测试
go test -v详细输出
go test -run=TestFoo精确匹配
go test -bench=. -benchmemBenchmark
go test -cover覆盖率
go test -race竞态检测
go test -short跳过慢测试

九、最佳实践

  • 测试命名清晰:TestParseDate_InvalidFormat_ReturnsError
  • 使用表驱动测试
  • 只测公共行为,不依赖内部实现
  • 保持测试快速、独立、可重复
  • 避免 time.Sleep,改用 channel/context