Files
OpenFlare/.agents/skills/go-testing/SKILL.md
T
2026-08-04 11:40:32 +08:00

6.0 KiB
Raw Blame History

name, description, license, compatibility, metadata, allowed-tools
name description license compatibility metadata allowed-tools
go-testing Use when writing, reviewing, or improving Go test code — including table-driven tests, subtests, parallel tests, test helpers, test doubles, and assertions with cmp.Diff. Also use when a user asks to write a test for a Go function, even if they don't mention specific patterns like table-driven tests or subtests. Does not cover benchmark performance testing (see go-performance). Apache-2.0 Uses github.com/google/go-cmp for cmp.Diff comparisons
sources
Google Style Guide, Uber Style Guide
Bash(bash:*)

Go 测试

快速参考

模式 使用场景
t.Error 默认 — 报告失败,继续运行
t.Fatal 设置失败或继续运行没有意义
cmp.Diff 比较 struct、slice、map、proto
表驱动 多个用例共享相同逻辑
子测试 需要过滤、并行执行或命名
t.Helper() 任何测试辅助函数(作为第一条语句调用)
t.Cleanup() 在辅助函数中进行清理,替代 defer

有用的测试失败信息

规范:测试失败必须在不阅读测试源码的情况下可诊断。

每条失败信息必须包含:函数名、输入、实际值(got)和期望值(want)。使用格式 YourFunc(%v) = %v, want %v。

// 好:
t.Errorf("Add(2, 3) = %d, want %d", got, 5)

// 不好:缺少函数名和输入
t.Errorf("got %d, want %d", got, 5)

始终先打印 got 再打印 want:got %v, want %v — 绝不反转。


不使用断言库

规范:不要使用断言库。对于复杂比较使用 cmp.Diff。

if diff := cmp.Diff(want, got); diff != "" {
    t.Errorf("GetPost() mismatch (-want +got):\n%s", diff)
}

对于 protocol buffers,添加 protocmp.Transform() 作为 cmp 选项。始终在 diff 信息中包含方向键 (-want +got)。避免比较 JSON/序列化输出 — 改为语义比较。

在编写自定义比较辅助函数或领域特定测试工具时,请阅读 references/TEST-HELPERS.md。


t.Error vs t.Fatal

规范:默认使用 t.Error 以在一次运行中报告所有失败。仅在无法继续时使用 t.Fatal。

选择 t.Fatal 的场景:

  • 设置失败(数据库连接、文件加载)
  • 下一个断言依赖于上一个断言成功(例如,编码后的解码)

绝不在测试 goroutine 以外的 goroutine 中调用 t.Fatal/t.FailNow — 改为使用 t.Error。

在编写需要在 t.Error 和 t.Fatal 之间选择的辅助函数时,或需要两者的详细示例时,请阅读 references/TEST-HELPERS.md。


表驱动测试

在搭建新的表驱动测试并需要标准的 struct、循环和子测试布局时,请参阅 assets/table-test-template.go。

建议:当多个用例共享相同逻辑时使用表驱动测试。

使用表测试的场景: 所有用例运行相同的代码路径,没有条件设置、mock 或断言。单个 shouldErr bool 是可以接受的。

不使用表测试的场景: 用例需要复杂设置、条件 mock 或多个分支 — 改为编写单独的测试函数。

关键规则:

  • 当用例跨越多行或有相同类型的相邻字段时,使用字段名
  • 在失败信息中包含输入 — 绝不通过索引标识行

在编写表驱动测试、子测试或并行测试时,请阅读 references/TABLE-DRIVEN-TESTS.md。

验证:在生成或修改测试后,运行 go test -run TestXxx -v 验证测试能编译并通过。在继续之前修复任何编译错误。


测试辅助函数

规范:测试辅助函数必须首先调用 t.Helper() 并使用 t.Cleanup() 进行清理。

func setupTestDB(t *testing.T) *sql.DB {
    t.Helper()
    db, err := sql.Open("sqlite3", ":memory:")
    if err != nil {
        t.Fatalf("Could not open database: %v", err)
    }
    t.Cleanup(func() { db.Close() })
    return db
}

在编写测试辅助函数、清理函数或自定义比较工具时,请阅读 references/TEST-HELPERS.md。


测试错误语义

建议:测试错误语义,而非错误消息字符串。

// 不好:脆弱的字符串比较
if err.Error() != "invalid input" { ... }

// 好:语义检查
if !errors.Is(err, ErrInvalidInput) { ... }

对于不需要特定语义的简单存在性检查:

if gotErr := err != nil; gotErr != tt.wantErr {
    t.Errorf("f(%v) error = %v, want error presence = %t", tt.input, err, tt.wantErr)
}

测试组织

在使用测试替身、选择测试包位置或规划测试设置范围时,请阅读 references/TEST-ORGANIZATION.md。

在设计可重用的测试验证函数时,请阅读 references/VALIDATION-APIS.md。


集成测试

在编写 TestMain、验收测试或需要真实 HTTP/RPC 传输层的测试时,请阅读 references/INTEGRATION.md。


可用脚本

  • scripts/gen-table-test.sh — 生成表驱动测试脚手架
bash scripts/gen-table-test.sh ParseConfig config > config/parse_config_test.go
bash scripts/gen-table-test.sh --parallel ParseConfig config      # 带 t.Parallel()
bash scripts/gen-table-test.sh --output config/parse_config_test.go ParseConfig config

相关 Skill

  • 错误测试:在使用 errors.Is/errors.As 或哨兵错误测试错误语义时,请参阅 go-error-handling
  • 接口 mock:在消费端通过实现接口创建测试替身时,请参阅 go-interfaces
  • 测试函数命名:在命名测试函数、子测试或测试辅助工具时,请参阅 go-naming
  • Linter 集成:在 CI 或 pre-commit hooks 中与测试一起运行 linter 时,请参阅 go-linting