Go测试如何共享测试数据_Go测试数据复用方案

优先用testdata/目录存放原始测试数据,动态生成数据才封装进internal/testutil或xxx_test包;TestMain不可用于预加载共享数据;表驱动测试用只读包级变量定义用例;跨包复用需提取到internal/testdata。

测试数据该定义在 testutil 包还是直接放 testdata/ 目录?

优先用 testdata/ 目录存放原始测试数据(如 JSON 文件、CSV 样本、SQL dump),而非硬编码在 Go 源文件里。这样能避免污染测试逻辑,也方便人工校验和复用。

如果数据需要动态生成或带逻辑(比如构造含时间戳的 JWT、随机但符合规则的邮箱),才考虑封装进 testutil 包——但这个包必须是 internal/testutilxxx_test 后缀,防止被外部模块意外 import。

  • testdata/ 下的文件不会被 go build 打包,仅测试时可读(os.ReadFile("testdata/config.json")
  • 不要在 testdata/ 里放 Go 源文件(如 testdata/fixtures.go),Go 测试工具链不识别这种“伪测试依赖”
  • 路径写相对路径即可,testing.TBTempDir()testutil 工具函数都默认基于当前测试文件所在目录解析

TestMain 能不能用来预加载共享数据?

不能。Go 的 TestMain 是包级入口,只运行一次,但它无法安全共享状态给并行测试(t.Parallel()),且一旦某个测试 panic,后续测试可能拿到损坏的全局变量。

真正安全的共享方式是「惰性初始化 + sync.Once」配合包级变量,或者更推荐:每个测试自己调用工厂函数获取干净副本。

func newSampleUser() User {
    return User{
        ID:       123,
        Name:     "alice",
        Email:    "alice@example.com",
        Created:  time.Now().UTC().Truncate(time.Second),
    }
}

func TestCreateUser(t *te

sting.T) { u := newSampleUser() // 修改字段仅影响当前测试 u.Email = "test-" + t.Name() + "@example.com" // ... }

表驱动测试中如何复用输入输出对?

把测试用例定义成包级变量(类型为切片),而不是在每个 TestXxx 函数里重复声明。注意:这些变量必须是只读结构(如 []struct{in, want string}),不能含指针或 map 等可变内嵌字段,否则多个测试并发修改会互相干扰。

  • var testCases = []struct{...}{...} 定义,放在 xxx_test.go 顶部
  • 如果某个测试需修改 case 数据,先 copy 再改,例如:c := testCase[i]; c.in = "modified"
  • 避免在 case 中直接引用 time.Now()rand.Intn() —— 这会让测试不可重现;改用固定种子或注入时间接口

跨包复用测试数据时为什么总报 “undefined”?

因为 Go 不允许非 _test 包直接 import xxx_test 包。常见错误是想让 pkgA 的测试代码复用 pkgBfixture.NewDB(),结果编译失败。

正确做法只有两个:

  • 把通用 fixture 提取到 internal/testdata(不是 testdata/!),并确保它不 import 任何业务包(否则破坏 internal 封装)
  • //go:build ignore + go run 临时脚本生成测试数据,不走 import 机制

别试图用符号链接或 replace 指向测试文件——go test 会跳过非 *_test.go 文件,且模块校验会失败。