本技能说明在各类 Go 仓库中如何编写测试,重点是“怎么写”:断言、表驱动用例、测试替身、助手函数、异步等待、golden 文件、模糊测试、基准测试与集成测试。它不回答“测试什么”,那部分属于仓库的 testing-policy;红绿重构循环则使用 tdd 技能。
主要约定包括:通过导出 API 在 foo_test 包做黑盒测试,仅当单元本身设计为不导出时用 package foo。断言输出与状态,而非调用次数,避免“变更探测器”式测试。测试替身按真实、fake、stub、mock 的忠实度顺序选择,mock 仅用于跨系统边界的状态变更调用,且手写记录器而非 mocking 库。fake 应有状态且行为诚实,同一契约套件同时跑 fake 与真实实现。
SQL 测试应通过 internal/pgtest 对真实 Postgres 执行;仓库若没有该包,可按技能资产安装,参考 references/integration-db.md。比较使用 cmp.Diff(want, got) 并以 (-want +got) 报告;若 go.mod 缺少 github.com/google/go-cmp,在首个测试中用 go get 加入,并同步修正相冲突的 lint 或文档。若明确限定“仅标准库”,标量用 ==,切片与 map 用 slices.Equal/maps.Equal,结构体逐字段比较;两种情况下都不用 reflect.DeepEqual。失败信息写成 Func(in) = got, want want,错误用 errors.Is/errors.As 匹配。表驱动仅用于所有用例检查方式相同的情况。
等待不要用 time.Sleep,改用通道、带截止时间的轮询,或在涉及定时器时用 synctest.Test(Go 1.25+)。t.Parallel() 仅用于不共享状态的测试,pgtest 数据库从不共享所以可并行。JSON 应解码比较而非按字节比较;golden 输出需先规范化。模糊测试用于不可信输入的解析器,提交 testdata/fuzz/。HTTP 处理器应通过真实路由与中间件测试。
运行方式:go test ./... 会跑包括数据库在内的全部测试,无构建标签、无 -short 跳过、无 make 目标;构建标签只用于端到端套件。缺少 Docker 或 TEST_DATABASE_URL 时 pgtest 会报错并同时点名两者,不要用 t.Skip 掩盖。完成前运行 go test -race ./... 与 golangci-lint run。