引入

写完代码不代表写对了,得验证。Go 内置了 testing 包,不需要第三方框架,写个 Test 函数就能跑测试。配合表驱动测试和 go test 命令,一套流程全搞定。

正文

定义

定义

Go 测试基于 testing 包,测试文件以 _test.go 结尾,测试函数以 Test 开头,签名为 func TestXxx(t *testing.T)。用 go test 命令运行。

语法

// add.go
func Add(a, b int) int {
    return a + b
}
 
// add_test.go
func TestAdd(t *testing.T) {
    got := Add(1, 2)
    if got != 3 {
        t.Errorf("Add(1, 2) = %d, want 3", got)
    }
}

例子

基本测试

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

t.Errorf() 报告失败但继续执行,t.Fatalf() 直接终止当前测试。

表驱动测试

func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"正数", 1, 2, 3},
        {"零", 0, 0, 0},
        {"负数", -1, -2, -3},
        {"混合", -1, 5, 4},
    }
 
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Add(tt.a, tt.b)
            if got != tt.expected {
                t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.expected)
            }
        })
    }
}

表驱动测试把多组用例塞进一个 slice,用 t.Run() 跑子测试,每个子测试独立命名,失败时一眼能看出哪组出了问题。

子测试

t.Run("空切片", func(t *testing.T) {
    got := Sum([]int{})
    if got != 0 {
        t.Errorf("got %d, want 0", got)
    }
})

t.Run() 创建子测试,支持单独运行,方便定位失败用例。

跳过测试

func TestSlow(t *testing.T) {
    if testing.Short() {
        t.Skip("跳过慢速测试")
    }
    // 耗时操作
}

t.Skip() 跳过不需要的测试,go test -shorttesting.Short() 返回 true

常见写法

写法说明
go test运行当前包测试
go test ./…运行所有包测试
go test -v显示详细输出
go test -run TestXxx只跑指定测试
go test -short启用短模式
go test -cover显示覆盖率
t.Errorf()报告失败,继续执行
t.Fatalf()报告失败,终止测试
t.Skip()跳过当前测试
t.Run(name, fn)创建子测试

特点

  • 测试文件必须以 _test.go 结尾
  • 测试函数必须以 Test 开头,参数是 *testing.T
  • 表驱动测试是 Go 社区的推荐写法,用例清晰易维护
  • t.Run() 支持子测试,可以单独运行某个用例
  • go test -cover 能统计代码覆盖率
  • 测试函数里不需要手动调 maingo test 自动发现并运行

理解

Go 测试的设计非常务实:内置 testing 包,零依赖就能跑。表驱动测试把输入输出整理成表,新增用例只要加一行。go test 一条命令搞定编译、运行、报告,开发体验很顺滑。

引出

测试能验证功能对不对,但代码跑得快不快呢?接下来看 Go 基准测试,学习怎么用 Benchmark 函数测量性能。