用途
该技能用于在 Go 代码库中编写或修改表驱动测试(table-driven tests),确保测试遵循项目既定的模式。当需要编写测试、创建测试函数、添加测试用例,或用户提及相关需求时使用。
核心原则
- 一个测试函数,多个用例:定义测试用例切片,通过 t.Run() 迭代执行。
- 显式命名:每个用例都有 name 字段,作为子测试名称。
- 结构化输入:使用结构体字段承载输入、期望输出和配置。
- 辅助函数:在测试辅助函数中使用 t.Helper(),以获得正确的行号报告。
- 环境守卫:当凭证不可用时跳过集成测试。
表结构模式
测试表通常定义为匿名结构体切片,字段包括:name(必需,子测试名称)、input(函数输入)、want(期望输出)、wantErr(期望错误,成功时为 nil)、errCheck(可选,自定义错误校验函数)、setupEnv(可选,环境设置函数,返回清理函数)。随后通过 for 循环配合 t.Run(tt.name, func(t *testing.T) { ... }) 执行每个用例。
字段指南
- name:必需,子测试名称,应描述具体。
- input/args:视情况而定,被测函数的输入值。
- want/want*:视情况而定,期望输出值(如 wantErr、wantResult)。
- errCheck:可选,自定义错误校验函数。
- setupEnv:可选,环境设置函数,返回清理函数。
命名约定
- 测试函数:Test<FunctionName> 或 Test<FunctionName>_<Scenario>。
- 子测试名称:小写、描述性,允许空格。
- 输入字段:与参数名一致,或使用 input/args。
- 输出字段:以 want 为前缀(如 want、wantErr、wantResult)。
常见模式
- 基础表测试:定义 name 与输入字段的切片,迭代中调用被测函数并比较结果。
- 使用 wantErr 检查错误:用例包含 name、input、wantErr,迭代中使用 errors.Is(err, tt.wantErr) 比较。
- 使用 errCheck 自定义错误校验:用例包含 name、setupEnv、wantErr、errCheck,迭代中先执行 setupEnv 并 defer cleanup,再根据 errCheck 校验错误。
- 使用 setupEnv 设置环境:用例包含 name、setupEnv、options、wantErr,setupEnv 中设置环境变量并返回清理函数,迭代中 defer 清理后调用被测函数。
集成测试守卫
对于需要真实凭证的测试,使用 skipIfNoCreds 辅助函数:当 TIGRIS_STORAGE_ACCESS_KEY_ID 或 TIGRIS_STORAGE_SECRET_ACCESS_KEY 未设置时调用 t.Skip 跳过测试。该辅助函数内部使用 t.Helper()。
测试辅助函数
在辅助函数中使用 t.Helper() 以获得正确的行号报告。示例包括 setupTestBucket(创建测试桶)和 cleanupTestBucket(删除测试桶),两者均调用 t.Helper(),前者还调用 skipIfNoCreds(t)。
检查清单
编写表驱动测试时:
- 表结构体的 name 字段放在第一位。
- 每个测试用例都有描述性名称。
- 输入字段命名清晰(与参数一致或使用 input)。
- 期望输出字段以 want 为前缀。
- 迭代使用 t.Run(tt.name, func(t *testing.T) { ... })。
- 错误检查使用 errors.Is() 进行比较。
- 环境设置通过 defer 包含清理。
- 集成测试使用 skipIfNoCreds(t) 辅助函数。
- 测试辅助函数使用 t.Helper() 以获得正确的行号报告。
- 测试文件为 *_test.go,且与被测代码放在一起。
附加最佳实践
- 详细的错误消息:在错误消息中包含实际值和期望值,便于诊断失败,例如 t.Errorf("got %q, want %q", actual, expected)。注意 t.Errorf 不是断言,记录后测试会继续执行,这有助于判断失败是系统性的还是仅限特定用例。
- 使用 map 承载测试用例:map 的迭代顺序不确定,可确保测试用例真正相互独立。示例中以字符串为键、结构体为值定义测试表,迭代时使用 for name, tt := range tests 并调用 t.Run(name, ...)。
- 并行测试:添加 t.Parallel() 调用可并行运行测试用例,循环变量在每次迭代中自动捕获。
参考资料
- Go Wiki: TableDrivenTests —— Go 社区关于表驱动测试的官方最佳实践。
- Go Testing Package —— 标准库测试文档。
- Prefer Table Driven Tests —— Dave Cheney 关于何时以及为何使用表驱动测试而非传统测试结构的指南。