Unit Test(单元测试)
Go 使用标准库 testing 运行测试。生产代码放在普通 .go 文件中,测试文件以 _test.go 结尾;测试函数名以 Test 开头并接收 *testing.T。
表格驱动测试
生产文件 score.go:
package score
func Grade(value int) string {
if value >= 60 {
return "pass"
}
return "fail"
}
测试文件 score_test.go:
package score
import "testing"
func TestGrade(t *testing.T) {
tests := []struct {
name string
input int
want string
}{
{name: "pass boundary", input: 60, want: "pass"},
{name: "fail boundary", input: 59, want: "fail"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if got := Grade(test.input); got != test.want {
t.Fatalf("Grade(%d) = %q, want %q", test.input, got, test.want)
}
})
}
}
测试应验证可观察行为和失败边界,而不是复制实现细节。子测试名称应稳定、能定位场景;只有确认每个子测试互不共享可变状态时才使用 t.Parallel()。
Fixture、示例和基准
共享 fixture 可以用 t.Helper 标记辅助函数,用 t.Cleanup 注册资源清理。ExampleXxx 的 Output: 注释会把示例同时作为测试;BenchmarkXxx 用于在固定输入下测量变化,不能直接外推生产吞吐。Go 1.18 起可使用 FuzzXxx 探索边界输入。
常用命令:
go test ./...
go test -cover ./...
go test -race ./...
并发测试应同时覆盖取消、超时和资源退出;竞态检测不能证明没有死锁或业务逻辑错误。
常见错误
- 只测试成功路径,忽略错误、空输入、边界和取消。
- 在循环子测试中共享可变变量,尤其是并发子测试。
- 断言内部实现,导致无行为变化的重构也让测试失效。
- 忽略清理函数的错误或让测试依赖当前工作目录。
- 把覆盖率百分比或 benchmark 数字当作质量和生产性能的唯一结论。
小结
- 表格驱动测试适合覆盖多组输入和边界。
- 子测试、fixture、示例、基准、模糊测试和
-race解决不同问题。 - 测试必须验证失败路径,并保证资源和并发任务可以结束。