GO 语言单元测试入门

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


一、基本规范

规范 说明
测试文件 _test.go 结尾,通常与被测代码同包
测试函数 func TestXxx(t *testing.T)
运行 go test / go test -v
go 复制代码
// 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 记录错误 + 立即终止 前置条件失败
go 复制代码
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 推荐的测试模式:

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,均保证执行。

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

五、Benchmark 测试

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

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

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

go 复制代码
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() 让错误定位指向调用处:

go 复制代码
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=. -benchmem Benchmark
go test -cover 覆盖率
go test -race 竞态检测
go test -short 跳过慢测试

九、最佳实践

  • 测试命名清晰:TestParseDate_InvalidFormat_ReturnsError
  • 使用表驱动测试
  • 只测公共行为,不依赖内部实现
  • 保持测试快速、独立、可重复
  • 避免 time.Sleep,改用 channel/context
相关推荐
古城小栈1 小时前
Bun从Zig迁移至Rust:有何重大意义?
开发语言·后端·rust
虎子_layor1 小时前
给 Agent 接入新模型的推理模式:从配置开关到协议适配
后端·架构
IT_陈寒1 小时前
Java的Stream.peek()千万别乱用,血泪教训
前端·人工智能·后端
小江的记录本2 小时前
【MySQL】MySQL日志体系:redo log/undo log/binlog 三者区别、两阶段提交、如何保证数据一致性
java·数据库·后端·python·sql·mysql·面试
Jul1en_3 小时前
【Spring Cloud】Spring Cloud Config详解
后端·spring·spring cloud
Wy_编程3 小时前
go语言面向对象和异常处理
开发语言·后端·golang
易安说AI10 小时前
Codex 直接住进 JetBrains IDE 里:AI Agent 正在接管熟悉的开发入口
后端
子兮曰11 小时前
Node.js v26.1.0 深度解读:FFI、后量子密码与调试器的进化
前端·后端·node.js
Wy_编程11 小时前
go语言中的结构体
开发语言·后端·golang