Go 单元测试入门指南
用 Go 内置 testing 包写单元测试:项目搭建、编写与运行测试、处理失败、表驱动测试模式与代码覆盖率检查,一篇上手 Go 测试。
本文依据官方文档整理,未执行运行验证或性能基准。代码片段展示局部用法,业务函数、数据和环境需按项目补齐;版本与配置以所引文档为准。
直接回答:Go 标准库自带 testing 框架,无需任何第三方依赖:在被测代码旁建一个 _test.go 文件,写 Test 开头的函数,用 go test 运行——配合表驱动模式,几行代码就能覆盖大量场景。
Go 测试的基本约定
- 测试文件通常与被测文件同目录,可用同包或包名加 _test 的外部测试包,以 _test.go 结尾;
- 测试函数签名为
func TestXxx(t *testing.T); go test自动发现并执行。
这种"约定大于配置"的设计让 Go 测试几乎没有学习门槛。
搭建演示项目
mkdir gotest-demo && cd gotest-demo
go mod init gotest-demo
写个被测函数 math.go:
package main
func Add(a, b int) int {
return a + b
}
第一个测试
math_test.go:
package main
import "testing"
func TestAdd(t *testing.T) {
got := Add(1, 2)
if got != 3 {
t.Errorf("Add(1, 2) = %d, 期望 3", got)
}
}
注意 Go 的哲学:没有断言库,if + t.Errorf 就是断言。看似朴素,实则让测试代码就是普通 Go 代码,零魔法。
运行测试
go test ./... # 跑所有包
go test -v # 详细输出
go test -run TestAdd # 按名称过滤
处理失败
t.Errorf:记录失败但继续执行当前用例——适合一个用例里多个独立检查;t.Fatalf:终止当前测试goroutine(不能在后台goroutine里调用它来终止整条测试)——后续检查已无意义时使用(如初始化失败)。
表驱动测试:Go 的招牌模式
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"正数相加", 1, 2, 3},
{"负数相加", -1, -1, -2},
{"零值", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add(%d, %d) = %d, 期望 %d", tt.a, tt.b, got, tt.want)
}
})
}
}
表驱动片段替换前文同名TestAdd,不要把两个同名函数同时放进文件。新增场景只需往切片里加一行;t.Run 生成子测试,失败报告精确到场景名。这是 Go 社区最推崇的测试组织方式。
代码覆盖率
go test -cover # 输出覆盖率百分比
go test -coverprofile=c.out # 生成覆盖率文件
go tool cover -html=c.out # 浏览器查看逐行覆盖
HTML 视图里绿色是覆盖、红色是遗漏——盯关键路径的红色区域补用例,比追求总百分比实在。
常见问题(FAQ)
Q:需要引入 testify 这类断言库吗?
A:看团队口味。标准写法啰嗦但零依赖;testify 的 assert.Equal 表达力更强、失败信息更友好。大项目引入 testify 是常见选择,小项目标准库足够。
Q:测试文件能和被测文件不同包吗?
A:可以,用 xxx_test 包名(黑盒测试),只能访问公开 API。想测未导出函数就用同包(白盒)。两种可以共存。
Q:怎么跳过某个测试?
A:函数开头 t.Skip("原因")。配合 testing.Short() 可以实现"短模式跳过重测试",CI 快速通道很实用。
官方参考
资料核对日期:2026-09-29。