测试
go test 是 Go 内置的测试工具链:测试代码与源码同目录存放(*_test.go),无需第三方框架即可覆盖单元、接口与基准测试。没有测试的生产代码不应合入主干,这是 Go 团队的工程共识。
测试基础
测试函数以 Test 开头、参数为 *testing.T,放在同包的 _test.go 文件中:
表驱动测试:Go 的标志性格式
同一逻辑覆盖多组输入输出时,使用"用例切片 + 循环断言"的表驱动格式:
Tip
表驱动测试的价值:
- 新增用例只需加一行数据,断言逻辑零重复。
-run TestSlugify/中文可单独运行某个子测试。- 失败输出精确到用例名,定位成本极低。
断言选择:t.Fatalf 用于后续依赖该步骤的场景(失败即终止);普通断言用 t.Errorf 让所有用例跑完。
接口测试:httptest
net/http/httptest 提供两个层级的测试工具:ResponseRecorder 内存化单次请求,NewServer 启动真实监听。
需要测试完整链路(路由、中间件、序列化)时,用 httptest.NewServer 启动真实服务:
依赖替换:小接口与替身
生产代码依赖外部服务(数据库、第三方 API)时,测试必须隔离它们。Go 的做法是定义小接口,注入假实现,而非重度 mock 框架:
:::tip 替身选择经验:
- Fake(内存实现):默认选择,还可顺带验证业务逻辑。
- Stub:固定返回值,用于覆盖特定分支。
- 接口方法很多时再考虑
gomock、counterfeiter等代码生成工具;小接口手写 fake 通常更快。 - 测试第三方库提供的接口时优先使用其官方测试工具(如
sqlmock)。 :::
基准测试与竞态检测
:::warning 三条铁律:
- 测试文件与被测代码同包(白盒)或同目录外包
package xxx_test(黑盒);对外 API 优先黑盒测试。 - 并发代码必须在
-race下通过,否则视为测试未通过。 - 测试要快速且相互独立:不依赖执行顺序、不依赖外部网络,需要真实依赖时用 Docker 或 testcontainers。 :::
小结
- 表驱动 + 子测试是 Go 单元测试的标准格式。
httptest覆盖 handler 单测与真实监听两级接口测试。- 依赖注入小接口 + 手写 fake,比 mock 框架更符合 Go 风格。
- CI 中永远开启
-race,基准测试用b.Loop/b.N编写。