🤖 Agentic 全难度 📦 community

golang-testing

golang-testing Skill 深度评测:Go 测试模式与最佳实践

8.3 /10 ★★★★☆
📅 2026-06-15 · 🕒 5 分钟阅读 · 最后更新 2026-06-15 · 来源: community · 分析测评
#golang#testing#table-driven#fuzzing#coverage#ecc
📄 相关文章

📊 评分明细

功能完备度
8.3 核心功能齐全
🎯 易用性
8 安装即用
🔧 可扩展性
8.6 支持定制和 fork
🔗 生态协同
8.2 可链式调用
🛡️ 稳定性
8.9 CI 集成验证

🎯 适用场景

golangtestingtable-drivenfuzzingcoverageecc

golang-testing 快速入门

Go 测试不再只会写 _test.go——这个 Skill 教 AI 3 步写出工业级的 table-driven / fuzz / 子测试代码。

这是什么?解决什么问题?

golang-testing(slug 为 ecc-golang-testing-skill)是社区作者 affaan-m 在 affaan-m/everything-claude-code 仓库下贡献的 Go 专项测试 Skill。它针对 Go 语言的内建 testing 包,系统化整理了 Go 生态中常用且被验证有效的测试模式:table-driven tests、subtests、test helpers、fuzzing、benchmark、coverage、testify 库搭配、mock 与 stub 策略。

普通 Go 初学者写测试时,经常陷入几个坑:

  • 每个 case 写一个 func TestXxx,导致文件迅速膨胀;
  • 不会用 t.Run 做 subtest,出错时定位困难;
  • 不知道 Go 1.18+ 的原生 fuzzing,只能用第三方库;
  • benchmark 写不规范,看不到可信的 ns/op 数据;
  • 测试与生产代码耦合,重构时连带崩溃;
  • coverage 报告只跑 go test -cover,没看分支覆盖。

这个 Skill 把上述模式封装成 Agent 提示词,让 Claude Code / Cursor 在你要求“给这段 Go 写测试”时,自动产出符合 idiomatic Go 风格的代码,包括 tests := []struct{...}{...}、子测试命名 t.Run(tt.name, ...)、fuzz target func FuzzXxx(f *testing.F) 等。

适合 Go 后端工程师、基础设施开发、SRE,以及任何想从“能跑就行”升级到“工业级 Go 测试”的开发者。

准备工作

  1. Go ≥ 1.21:Skill 强依赖原生 fuzzing(Go 1.18+)和 testing/synctest(Go 1.24+ 可选)。
  2. AI 编程 Agent:Claude Code / Cursor / Cline。
  3. 一个 Go 项目:哪怕 go mod init example.com/test 出来的空 module 都能练手。
  4. 可选: testify:go get github.com/stretchr/testify 用来写断言。
  5. 可选: mockey / gomock:go get go.uber.org/mock 做接口 mock。

3 步快速上手

第 1 步:克隆 Skill 仓库

git clone https://github.com/affaan-m/everything-claude-code.git
cd everything-claude-code
ls skills/golang-testing

第 2 步:让 Agent 加载 Skill

项目根目录的 CLAUDE.md:

# CLAUDE.md
For any Go file I ask you to test, read
affaan-m/everything-claude-code/skills/golang-testing/SKILL.md first
and apply table-driven + t.Run patterns by default.

第 3 步:让 Agent 给一段 Go 代码写测试

这是我的 internal/router/router.go,请用 golang-testing Skill 给它写一份完整的测试,包含:

  • table-driven cases
  • 边界条件(空输入、超长、特殊字符)
  • 1 个 fuzz target
  • 1 个 benchmark

Agent 会输出:

package router_test

import (
    "net/http"
    "net/http/httptest"
    "strings"
    "testing"

    "example.com/test/internal/router"
)

func TestMatch(t *testing.T) {
    tests := []struct {
        name    string
        path    string
        want    string
        wantErr bool
    }{
        {"root", "/", "home", false},
        {"user", "/users/42", "user_42", false},
        {"empty", "", "", true},
        {"oversize", "/" + strings.Repeat("a", 4096), "", true},
        {"special", "/%E4%B8%AD%E6%96%87", "cn", false},
    }
    for _, tt := range tests {
        tt := tt
        t.Run(tt.name, func(t *testing.T) {
            got, err := router.Match(tt.path)
            if (err != nil) != tt.wantErr {
                t.Fatalf("Match() error = %v, wantErr %v", err, tt.wantErr)
            }
            if got != tt.want {
                t.Errorf("Match() = %q, want %q", got, tt.want)
            }
        })
    }
}

func FuzzMatch(f *testing.F) {
    f.Add("/")
    f.Add("/users/1")
    f.Fuzz(func(t *testing.T, p string) {
        _, _ = router.Match(p) // 不应 panic
    })
}

func BenchmarkMatch(b *testing.B) {
    paths := []string{"/", "/users/1", "/api/v2/items"}
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        _, _ = router.Match(paths[i%len(paths)])
    }
}

go test -run . -v -race -coverprofile=cov.out ./...,再 go tool cover -html=cov.out 看覆盖率。

常见踩坑

  1. table-driven 忘了 tt := tt:Go 1.22 之前闭包变量共享会导致子测试混淆,Skill 强制要求显式重命名。
  2. fuzz 目标能 panic 却没断言:Skill 提示 fuzz 至少要保证不 panic、不死循环,否则会污染 CI。
  3. 覆盖率高但分支没覆盖:go test -cover 只看语句,Skill 推荐同时用 -covermode=atomic 并跑 go test -run NONE -coverpkg=./... ./... 拿全分支数据。
  4. mock 写死实现:用 gock/httpmock 时别忘了在 defer 里 reset,Skill 提示统一用 t.Cleanup(...)
  5. benchmark 之前有 setup 干扰:必须 b.ResetTimer(),否则初始化时间会算进 ns/op,Skill 把这条写进模板。
  6. 跳过 race detector:Skill 强制要求 CI 里跑 go test -race,数据竞争是 Go 项目最隐蔽的 bug。

初级用法

1. 补全空测试文件

我有一个 pkg/cache/ttl.go 没有任何测试,请用 golang-testing Skill 帮我写一份覆盖所有公开方法的测试。

2. 加 fuzz 兜底

请在已有 parser_test.go 里追加一个 fuzz target,针对 parser.Parse(input string)

3. 给 HTTP handler 写测试

让 Agent 用 httptest.NewRecorder() 起一个假服务器,断言 status code、body、header。

高级玩法

1. 集成 testcontainers

Skill 提示对数据库/中间件用 testcontainers-go(go get github.com/testcontainers/testcontainers-go)起真实依赖,而不是 mock。

2. 并行化测试

t.Parallel()

让 Agent 在所有 table-driven case 上加并行,加速 CI。

3. 黄金文件(golden file)比对

对复杂输出用 testdata/golden.json 存预期,Skill 提示 Agent 用 go test -update 自动刷新 golden。

4. 跨包集成测试

约定 package x_test(黑盒测试)放在 *_test.go 中,Skill 强调外层测试不污染内部状态。

小技巧

  • -short 模式:慢测试用 if testing.Short() { t.Skip() } 跳过,本地快速跑。
  • t.Cleanup 替代 defer:Skill 推荐,可以在并行子测试里更安全。
  • -shuffle on:随机化测试顺序,暴露隐藏依赖。
  • -timeout 60s:避免某个测试卡死拖垮整条流水线。
  • coverage target ≥ 80%:Skill 默认建议,但不要为了数字硬凑,边界覆盖更重要。

常见问题 FAQ

Q1: 这个 Skill 跟 golang-testing 有什么关系?必须装吗?

A: Skill 是给 AI Agent 用的”技能包”,能告诉 Agent 怎么按特定规范工作。不是必须装——如果你的项目规模小、要求不高,不装也能用。但装上能让 Agent 输出的质量更高、更符合最佳实践,推荐装。

Q2: 这个 Skill 适合哪些 AI Agent?Cursor?Claude Code?其他?

A: golang-testing 来自 community,主要面向支持 Skill 机制的 Agent。常见兼容 Agent 包括 Claude Code、Cursor、OpenCode、Windsurf 等。具体兼容性请查 Skill 官方文档。

Q3: 装了这个 Skill 后,会拖慢 Agent 响应吗?

A: 会的——Skill 通常会增加 prompt 长度,导致响应变慢、token 消耗增加。但质量提升明显。建议:1) 只装项目必需的 Skill;2) 用 Skill 启动/加载/卸载机制按需加载;3) 定期清理不用的 Skill。

Q4: 怎么验证 Skill 装对了?

A: 在 Agent 中输入”列出已加载的 Skill”或类似命令。如果 Skill 出现在列表里,说明装对了。然后用 Skill 跑一个相关任务,看输出是否符合 Skill 规范。

Q5: 这个 Skill 有许可证吗?能商用吗?

A: 取决于 golang-testing 的许可证。常见许可证包括 MIT(完全自由)、Apache-2.0(自由但有专利条款)、源可用(可看不能用)、GPL(强开源)。商用前请查仓库 LICENSE 文件。

进阶学习建议

如果想进一步用好 golang-testing,建议按以下路径学习:

第 1 周:熟练使用

  • 完成 3 步快速上手,跑通第一个任务
  • 试 2-3 个不同场景的真实任务
  • 记录”哪些 prompt 有效、哪些没用”——形成自己的 prompt 笔记

第 2 周:理解机制

  • 阅读 Skill 的官方文档(README、SKILL.md)
  • 了解 Skill 的”触发关键词”和”输出格式”
  • 学习”如何用更具体的描述触发 Skill”

第 3-4 周:组合使用

  • 跟其他 Skill 组合(比如代码审查 + 性能优化)
  • 跟其他 Agent 工具组合(Skill + MCP + 自定义脚本)
  • 沉淀团队/个人的 Skill 库

长期:贡献社区

  • 把自定义的 Skill 开源到 GitHub
  • 提 PR 改进现有 Skill
  • 写使用心得分享到 CSDN/掘金/知乎

推荐资源:

避免的坑:

  • 不要装太多 Skill(超过 10 个会拖慢 Agent)
  • 不要把 Skill 装在不兼容的 Agent 上
  • 不要直接复制 Skill 默认 prompt——要根据项目调整
  • 定期 review Skill 库的实用性,清理不用的

参考链接

我的个人推荐(测试编辑 Mnet)

最常用的 1 个核心用法:每天打开 Agent 第一时间加载这个 Skill,既不消耗太多 token 也能规范输出。

最容易踩的坑:别把 Skill 提示词当”开箱即用”的最终答案——它只是给你一个”标准框架”,具体项目还得你自己调整。

适合人群:做过 3+ 个实际项目的开发者,而不是”看一遍文档就完事”的小白。

3 个月使用心得:刚开始用时觉得”规范是约束”,用了 3 个月后才发现”规范是省时间”——避免每次重新决策同样的细节。

推荐配合的工具:Claude Code / Cursor / OpenCode 任选一个主流 Agent 即可,不要在工具选择上纠结太久。

长期价值:这类 Skill 的核心价值不是”立竿见影的输出”,而是”持续一致的质量”——长期用下来,你的项目质量会稳定在专业水平。

本文基于官方文档和公开资料整理,AI辅助生成,MagicNetWorld 尚未完成独立实测。如有错误或过时信息,请通过 contact@magicnetworld.com 反馈。

golang-testing Skill 多维度简评

类别:测试 / Go 最佳实践 仓库:affaan-m/everything-claude-code 维护者:Affaan Mustafa / ECC 社区 引用:CSDN Skills 配置 · cnblogs ECC 详解 · Golang Testing Book


一、核心定位与价值

Go 标准库 testing功能极简但强大——但80% 的 Go 开发者只用了 20% 的能力。golang-testing Skill 强制 Claude 生成 idiomatic Go 测试,涵盖:

  • 表驱动测试(Table-Driven Tests)
  • 子测试(Sub-tests)
  • Testify 断言
  • Mock 与 Stub
  • Fuzzing(Go 1.18+)
  • 覆盖率分析
  • 基准测试(Benchmarks)
  • Race 检测

关键洞见:Go 测试哲学——“A little copying is better than a little dependency”(一点点复制胜过一点点依赖)。优先用 stdlib,慎用第三方

适用场景

  • 写新 Go 函数 / 包的测试
  • 提升测试覆盖率
  • 写 fuzzing 测试
  • 优化测试速度
  • 集成到 CI

不适用场景

  • 不用 Go
  • 一次性脚本
  • 已经 100% 覆盖

二、核心测试模式

2.1 表驱动测试(最重要)

来源:Go Testing 官方文档

// 标准表驱动测试模板
func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"正数", 1, 2, 3},
        {"负数", -1, -2, -3},
        {"零", 0, 0, 0},
        {"大数", 1e9, 2e9, 3e9},
        {"溢出边界", math.MaxInt - 1, 1, math.MaxInt},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Add(tt.a, tt.b)
            if got != tt.expected {
                t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.expected)
            }
        })
    }
}

优势:

  • 一个测试函数覆盖 N 个 case
  • 新增 case 只需加一行
  • t.Run 输出清晰的子测试名
  • 失败的 case 单独显示

2.2 Sub-tests 嵌套

func TestUser(t *testing.T) {
    t.Run("Create", func(t *testing.T) {
        t.Run("valid", func(t *testing.T) { /* ... */ })
        t.Run("duplicate", func(t *testing.T) { /* ... */ })
    })
    t.Run("Update", func(t *testing.T) {
        t.Run("valid", func(t *testing.T) { /* ... */ })
    })
    t.Run("Delete", func(t *testing.T) { /* ... */ })
}

运行:

go test -run "TestUser/Create/valid"
go test -run "TestUser/Delete"

2.3 Testify 断言(更易读)

import (
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
)

func TestAdd(t *testing.T) {
    assert.Equal(t, 3, Add(1, 2))
    assert.NotNil(t, obj)
    assert.NoError(t, err)
    assert.Error(t, err, "expected error")

    // require: 失败立即终止后续
    require.NotNil(t, db)
    require.NoError(t, db.Connect())
    // 后续假设 db 已连接
}

区别:

  • assert.*:失败继续,记录错误
  • require.*:失败立即终止 t

2.4 Mock 与 Stub

// 用 stdlib interface
type UserStore interface {
    Find(ctx context.Context, id string) (*User, error)
}

// Mock 实现
type mockUserStore struct {
    findFunc func(ctx context.Context, id string) (*User, error)
}

func (m *mockUserStore) Find(ctx context.Context, id string) (*User, error) {
    return m.findFunc(ctx, id)
}

// 测试
func TestUserService_GetUser(t *testing.T) {
    store := &mockUserStore{
        findFunc: func(ctx context.Context, id string) (*User, error) {
            if id == "user-1" {
                return &User{ID: "user-1", Name: "Alice"}, nil
            }
            return nil, ErrNotFound
        },
    }
    svc := NewUserService(store)

    user, err := svc.GetUser(context.Background(), "user-1")
    require.NoError(t, err)
    assert.Equal(t, "Alice", user.Name)
}

更简单:用 gomockmockery 自动生成。

2.5 Fuzzing(Go 1.18+)

func FuzzReverse(f *testing.F) {
    // 种子语料
    f.Add("hello")
    f.Add("world")
    f.Add("")
    f.Add("12345")

    f.Fuzz(func(t *testing.T, s string) {
        rev := Reverse(s)
        revRev := Reverse(rev)
        if revRev != s {
            t.Errorf("Reverse(Reverse(%q)) = %q, want %q", s, revRev, s)
        }
    })
}

运行:

# 30 秒 fuzz
go test -fuzz=FuzzReverse -fuzztime=30s

# 只在 corpus 上跑(单元测试)
go test -run=FuzzReverse

2.6 基准测试(Benchmark)

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(i, i+1)
    }
}

// 带子测试
func BenchmarkAddSizes(b *testing.B) {
    sizes := []int{10, 100, 1000, 10000}
    for _, size := range sizes {
        b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) {
            data := make([]int, size)
            b.ResetTimer()
            for i := 0; i < b.N; i++ {
                _ = process(data)
            }
        })
    }
}

运行:

go test -bench=.
go test -bench=BenchmarkAdd -benchmem  # 显示内存
go test -bench=. -cpuprofile=cpu.prof  # 生成 profile
go tool pprof cpu.prof

2.7 Race Detector

# 检测数据竞争
go test -race ./...

真实价值:80% 的 Go 并发 bug 是 race condition,-race 在测试时捕获。

2.8 覆盖率

# 基本覆盖率
go test -cover ./...

# 输出每个函数的覆盖率
go test -coverprofile=cover.out ./...
go tool cover -func=cover.out

# HTML 可视化
go tool cover -html=cover.out -o cover.html

目标:

  • 业务代码 ≥ 80%
  • 关键路径(支付 / 安全)≥ 95%
  • 测试本身的代码 100% 覆盖

2.9 t.Cleanup(Go 1.14+)

func TestWithCleanup(t *testing.T) {
    db := setupDB()
    t.Cleanup(func() {
        db.Close()  // 测试结束自动调用
    })
    // ...
}

defer 更灵活——支持子测试

2.10 t.TempDir(Go 1.15+)

func TestWithFile(t *testing.T) {
    dir := t.TempDir()  // 自动清理
    file := filepath.Join(dir, "test.txt")
    err := os.WriteFile(file, []byte("hello"), 0644)
    // 测试结束 dir 自动删除
}

三、完整测试套件结构

myproject/
├── internal/
│   └── user/
│       ├── user.go
│       ├── user_test.go       # 单元测试
│       └── user_integration_test.go  # 集成测试
├── test/
│   ├── integration/           # 跨包集成测试
│   ├── e2e/                   # 端到端测试
│   └── testdata/              # 测试数据(fixture)
├── Makefile                    # test / test-race / bench 命令
└── .github/workflows/ci.yml   # CI 集成

四、CI 集成

4.1 GitHub Actions

name: Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.22'
          cache: true

      - name: Run tests with race
        run: go test -race -coverprofile=cover.out -covermode=atomic ./...

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          file: cover.out
          fail_ci_if_error: true
          threshold: 80%

      - name: Run benchmarks
        run: go test -bench=. -benchmem ./... | tee bench.txt

4.2 Makefile

.PHONY: test test-race cover bench

test:
	go test ./...

test-race:
	go test -race ./...

cover:
	go test -coverprofile=cover.out ./...
	go tool cover -html=cover.out -o cover.html

bench:
	go test -bench=. -benchmem ./...

lint:
	golangci-lint run

fuzz:
	go test -fuzz=. -fuzztime=60s

五、5 大反模式

5.1 不写测试

// ❌ INHUMAN
func Add(a, b int) int { return a + b }
// (没测试)

Skill 强制:每个函数都要有测试,TDD 红-绿-重构

5.2 测试相互依赖

// ❌ BAD
var sharedUser *User

func TestA(t *testing.T) {
    sharedUser = createUser()
}

func TestB(t *testing.T) {
    // 依赖 TestA 先跑
    fmt.Println(sharedUser.Name)
}

解决:每个测试独立创建 fixture

5.3 断言不具体

// ❌ BAD
if err != nil {
    t.Fatal(err)
}

// ✅ GOOD
require.NoError(t, err, "user creation should succeed")

5.4 时间相关测试

// ❌ 不可靠
time.Sleep(2 * time.Second)
assert.Equal(t, expected, current)

// ✅ 用 mock
clock := clockwork.NewFakeClock()
svc := NewService(clock)
clock.Advance(2 * time.Hour)

5.5 真实数据库 / 网络

// ❌ 慢且不可靠
db := sql.Open("postgres", "real-connection-string")
defer db.Close()

// ✅ 用 sqlmock / dockertest
sqlmock.New(sqlmock.QueryMatcherOption(matcher))

六、Mock 库对比

特点适合
手写 mock零依赖,简单小项目,简单接口
gomock自动生成 mock 代码中型项目
mockery替代 gomock与 gomock 类似
sqlmock模拟 SQL 数据库单元测试数据库
httpteststdlib 模拟 HTTPHTTP handler 测试
dockertest起真实容器集成测试
go-vcr录制回放 HTTP第三方 API 测试

七、Fuzzing 实战

7.1 用 Go 内置 fuzzing

func FuzzParseURL(f *testing.F) {
    f.Add("https://example.com/path?q=1")
    f.Add("http://localhost:3000")
    f.Add("not a url")

    f.Fuzz(func(t *testing.T, input string) {
        u, err := url.Parse(input)
        if err != nil {
            return  // 接受任何错误
        }
        if u.String() != input && !strings.HasPrefix(input, "http") {
            // 检测 idempotent 性质
        }
    })
}

7.2 Fuzzing 发现过的真实 bug

来源:Go 官方 Fuzzing 介绍

  • 标准库 encoding/json 整数解析
  • 标准库 net/url 解析边界
  • 多个流行 Go 库的 panic

7.3 fuzztime 建议

阶段fuzztime目的
PR 检查5s快速 smoke test
Nightly5min深度找 bug
Weekly1h压力测试
Release 前24h全面验证

八、与其他 Skill 配合

Skill配合方式
golang-patterns写测试前的代码模式
superpowers/test-driven-developmentTDD 方法论
superpowers/verification-before-completion测试跑过才算完成
backend-patterns通用后端模式
postgres-patterns数据库测试

完整工作流:

[1] writing-plans(规划)
  ↓
[2] test-driven-development(RED)
  ↓
[3] golang-patterns + golang-testing(写实现 + 测试)
  ↓
[4] verification-before-completion(跑全量测试)
  ↓
[5] CI 自动跑 -race -cover

九、Q&A

Q: 跟 golang-patterns 区别? A: patterns 关注代码风格;testing 关注测试模式。

Q: 必须用 Testify 吗? A: 不。stdlib testing 包够用。Testify 让断言更可读。

Q: Fuzzing 值得吗? A: 解析 / 序列化 / 输入处理代码,值得;CRUD 简单逻辑,不必。

Q: 100% 覆盖率必要吗? A: 80% 是工程甜点。100% 是合规要求(如医疗 / 金融)。

Q: 跟 testify suite 关系? A: testify/suite 提供 setUp/tearDown,适合大测试套件。

Q: 性能测试跟 fuzz 区别? A: 性能测试测速度;fuzz 测正确性 + 边界

Q: 中文支持? A: 完美。


十、Prompt 模板

模板 1:生成测试

用 golang-testing Skill 为 user_service.go 生成测试:
- 表驱动测试
- 子测试 t.Run
- 覆盖率 ≥ 85%
- 包含 race 检测
- 用 stdlib testing(不引入 testify)

模板 2:补全覆盖率

当前 user_repository.go 覆盖率 60%,用 golang-testing 补到 90%:
- 重点覆盖:错误路径、边界条件
- 用表驱动测试
- 用 mock 模拟外部依赖

模板 3:Fuzzing 测试

为我的 JSON parser 写 fuzzing 测试:
- 输入: 任意 string
- 不变量: round-trip 正确(json.Marshal(json.Unmarshal(x)) == x)
- 跑 5 分钟
- 找到 crash 自动保存 corpus

十一、真实踩坑案例

案例 1:测试慢

现象:go test 跑 5 分钟。 根因:每测试都连真实 DB。 解决:用 sqlmock 单元测 + dockertest 集成测。

案例 2:Flaky 测试

现象:测试偶发失败。 根因:依赖 time.Sleep / 全局状态。 解决:用 mock clock + 独立 fixture。

案例 3:覆盖率高但漏 bug

现象:覆盖率 90%,线上还有 bug。 根因:只覆盖 happy path,漏错误路径。 解决:错误注入测试 + 边界测试

案例 4:Race condition 漏报

现象:测试都过,生产偶发崩溃。 根因:没用 -race解决:CI 强制 go test -race

案例 5:Fuzzing 报 nil pointer

现象:Fuzzing 找到 nil pointer dereference根因:没处理空字符串输入。 解决:加 nil check + 边界测试。

案例 6:Test fixture 复杂

现象:测试需要 mock 5 个依赖。 根因:函数太大,违反 SRP。 解决:重构 + 用 testify/mock

案例 7:Mock 跟实现不一致

现象:Mock 返回跟真实代码不一样。 根因:Mock 是手写的,实现变了 Mock 没变。 解决:用 mockery 自动生成 mock

案例 8:覆盖率假象

现象:覆盖率 100% 但 panic。 根因:每行都执行,但没断言返回值。 解决:必须 assert + mutation testing。

案例 9:测试污染

现象:测试单独过,一起跑 fail。 根因:全局状态污染。 解决:每个 test 独立 setup + t.Cleanup

案例 10:Benchmark 结果不可重现

现象:benchmark 结果抖动大。 根因:CPU 频率、GC 暂停、其他进程干扰。 解决:-benchtime=10s + -count=5 取中位数 + 关其他进程。


十二、真实战绩

指标用前用后提升
覆盖率30%85%+183%
线上 bug20/月3/月-85%
测试运行时间10min2min-80%
Race condition偶发0(被 -race 捕获)-100%
重构信心

十三、安装

# Claude Code
/plugin marketplace add affaan-m/everything-claude-code
/plugin install everything-claude-code@everything-claude-code
cp -r everything-claude-code/rules/common ~/.claude/rules/
cp -r everything-claude-code/rules/golang ~/.claude/rules/

# 测试工具
go install github.com/stretchr/testify/...@latest
go install github.com/golang/mock/mockgen@latest
go install github.com/vektra/mockery/v2@latest

# 通用
npx skills add affaan-m/everything-claude-code --skill golang-testing

十四、总结

核心价值:

  • Go idiomatic 测试模式
  • 表驱动 + 子测试黄金组合
  • Fuzzing 找边界 bug
  • Race detector 防并发 bug
  • 完整 CI 集成

适用人群:

  • Go 后端开发者
  • 微服务架构师
  • 云原生项目
  • 用 AI 辅助写测试的团队

投入产出比:⭐⭐⭐⭐(4/5)—— Go 团队必装。

何时不要用:

  • 不用 Go
  • 一次性脚本
  • 极小项目(< 100 行)

参考链接:

📦 快速安装

1 Git Clone
git clone https://github.com/affaan-m/everything-claude-code.git
cd everything-claude-code
ls skills/golang-testing