测试

翻译整理自 Testing 与 Testacular - Add test coverage。

Go 内置测试框架,无需第三方库。

1. 测试文件命名

源文件 greetings.go,测试文件命名为 greetings_test.go,包名与被测代码相同或加 _test 后缀:

package greetings

import "testing"

func TestHello(t *testing.T) {
    got := Hello("Go")
    want := "Hello, Go"
    if got != want {
        t.Errorf("got %q, want %q", got, want)
    }
}

运行测试:

go test
go test -v          # 详细输出
go test -cover      # 覆盖率
go test -run TestHello  # 只跑指定名字
go test ./...       # 当前模块所有包

2. 表驱动测试 Table-Driven

Go 推荐使用表驱动方式:

func TestAdd(t *testing.T) {
    tests := []struct {
        a, b, want int
        name       string
    }{
        {1, 2, 3, "two positives"},
        {0, 0, 0, "zeros"},
        {-1, 1, 0, "neg+pos"},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Add(tt.a, tt.b)
            if got != tt.want {
                t.Errorf("Add(%d,%d)=%d, want %d", tt.a, tt.b, got, tt.want)
            }
        })
    }
}

t.Run 启动子测试,便于独立定位失败:

go test -run TestAdd/two_positives

3. 基准测试 Benchmark

文件中 _test.go 后缀,函数名 BenchmarkXxx(b *testing.B):

func BenchmarkSprintf(b *testing.B) {
    for i := 0; i < b.N; i++ {
        fmt.Sprintf("%d", i)
    }
}

运行:

go test -bench .
go test -bench . -benchmem    # 显示内存分配

输出形如 BenchmarkSprintf-8 30000000 40.2 ns/op 16 B/op 1 allocs/op。

4. 示例测试 Example

写在 ExampleXxx 函数中,输出会与 // Output: 注释比对:

func ExampleHello() {
    fmt.Println(Hello("Go"))
    // Output: Hello, Go
}

非常适合做文档示例(pkg.go.dev 自动展示)。

5. TestMain 全局 setup/teardown

func TestMain(m *testing.M) {
    setup()
    code := m.Run()
    teardown()
    os.Exit(code)
}

6. 失败辅助

t.Error("失败但继续")        // 类似 log.Print + continue
t.Errorf("带格式失败")
t.Fatal("立即失败")          // 类似 log.Fatal + return
t.Fatalf("立即失败带格式")
t.Skip("跳过该用例")
t.Logf("记录日志")

7. httptest 测试 HTTP

func TestHandler(t *testing.T) {
    req := httptest.NewRequest("GET", "/users/1", nil)
    rec := httptest.NewRecorder()

    handler(rec, req)

    if rec.Code != http.StatusOK {
        t.Errorf("status=%d", rec.Code)
    }
}

8. testify 等第三方库

可选用的扩展库:

  • github.com/stretchr/testify:assert、mock、suite
  • github.com/DATA-DOG/godog:BDD
  • github.com/stretchr/mock:接口 mock

但官方测试包足以覆盖 90% 场景,建议先用标准库。

小结

Go 测试简单、统一、零配置,CI 中只需 go test ./...。配合基准测试、表驱动、子测试,可形成高质量工程能力。下一章学习 Go 1.18 引入的泛型。