测试工具函数必须接收testing.T或testing.B,首参数须为测试上下文;应统一放在testutil包中,用t.Cleanup()管理清理,写入操作用t.TempDir(),禁止硬编码路径或os.Chdir()。

测试工具函数必须接收 *testing.T 或 *testing.B
Go 的测试框架要求所有测试辅助函数显式接收 *testing.T 或 *testing.B,否则无法正确报告失败、跳过或计时。直接在工具函数里调用 t.Fatal() 或 b.ResetTimer() 是合法的,但前提是参数传进来了。
常见错误是写一个无参的 setupDB(),然后在测试里调用它——一旦内部出错,测试会 panic 而非标记为失败,CI 里难以定位。
- 所有可复用的 setup/teardown 工具函数,首参数必须是
*testing.T(或*testing.B) - 避免在工具函数中隐式依赖全局
testing.T实例(Go 不提供) - 如果需要提前终止测试,用
t.Fatalf(),不要用log.Fatal()或os.Exit()
用 testutil 包统一管理测试工具,不放 main_test.go
把测试工具散落在各个 _test.go 文件里会导致重复、版本不一致、难以发现。应该新建 testutil/ 目录,导出清晰命名的函数,比如 testutil.NewTestDB(t)、testutil.MustReadFile(t, "fixture.json")。
这个包本身不依赖具体业务逻辑,只依赖 testing 和标准库,方便跨项目复用。
立即学习“go语言免费学习笔记(深入)”;
-
testutil包的go.mod应该独立,不引入业务依赖 - 导出函数名带
Must表示失败时直接t.Fatal(如testutil.MustTempDir(t)) - 避免在
testutil中做耗时操作(如拉镜像、启 HTTP server),除非明确用于集成测试场景
测试工具要支持 cleanup,优先用 t.Cleanup()
Go 1.14+ 的 t.Cleanup() 是管理资源释放的最简方式:注册的函数会在当前测试结束(无论成功失败)时执行,且后注册的先执行,天然支持嵌套和并发测试隔离。
比起手动 defer 或全局 map 管理 cleanup 函数,t.Cleanup() 更轻量、更可靠。
- 在 setup 函数里,立刻调用
t.Cleanup()注册 teardown 逻辑 - 避免在
t.Cleanup()里调用t.Fatal()—— 它只用于清理,不参与测试结果判定 - 如果工具需支持旧版 Go,可用
defer+ 显式 error 检查,但注意 panic 会绕过 defer
测试数据路径要用 t.TempDir(),别硬编码 ./testdata
硬编码相对路径(如 "./testdata/config.yaml")会让测试在非项目根目录运行时失败,也妨碍 go test ./... -run=xxx 的任意子目录执行。
t.TempDir() 返回当前测试专属的临时目录,自动清理,且路径唯一,适合写入 mock 文件、启动本地服务、存放生成的证书等。
- 读取 fixture 数据时,用
filepath.Join("testdata", "input.json")是 OK 的(只要确保 testdata 在 module 根目录) - 但所有「写入」操作必须用
t.TempDir(),包括创建临时 DB 文件、dump 日志、生成 keypair - 不要在测试工具里调用
os.Chdir()—— 会影响同进程其他测试,且t.TempDir()已解决路径问题
t.Cleanup() 的 setup 函数,和没关数据库连接的 defer,本质上是一类问题。










