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
相关推荐
程序猿DD3 小时前
OctaFuse Gateway 2.9.0:用户限流控制、自定义转发头与管理后台升级
后端·api
三千星3 小时前
Java开发者转型AI工程化Week 5:让RAG学会思考、看见与自检
后端
一个Ai的杂货铺3 小时前
exit 0 也会撒谎:一个"绿灯盲跑"了一个月的定时任务,尸检报告
后端
北漂EDA码路3 小时前
现代 C++20:move、forward 与完美转发,EDA 大型程序为什么离不开它
后端
泡海椒3 小时前
JQuick-Java快速入门教程:轻量级规则引擎环境搭建与首个脚本运行实战
后端
stark张宇4 小时前
分布式事务最全图解(6种方案):从强一致的2PC到最终对账,彻底搞懂数据一致性
分布式·后端
IT毕设实战小研4 小时前
基于大数据的WTA职业网球赛事演变与竞技格局数据可视化分析
大数据·后端·爬虫·python·信息可视化·课程设计
IT_陈寒5 小时前
Java字符串判等踩坑记:==和equals真的不能乱用
前端·人工智能·后端
小马过河R5 小时前
微信小程序自定义登录态维护:从入门到生产级落地
后端·微信小程序·小程序·架构·登录态
计算机学姐5 小时前
基于SpringBoot的高校爱心慈善管理系统
java·vue.js·spring boot·后端·spring·tomcat·mybatis