golang-testing
golang-testing Skill 深度评测:Go 测试模式与最佳实践
评分明细
适用场景
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 测试”的开发者。
准备工作
- Go ≥ 1.21:Skill 强依赖原生 fuzzing(Go 1.18+)和
testing/synctest(Go 1.24+ 可选)。 - AI 编程 Agent:Claude Code / Cursor / Cline。
- 一个 Go 项目:哪怕
go mod init example.com/test出来的空 module 都能练手。 - 可选: testify:
go get github.com/stretchr/testify用来写断言。 - 可选: 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 看覆盖率。
常见踩坑
- table-driven 忘了
tt := tt:Go 1.22 之前闭包变量共享会导致子测试混淆,Skill 强制要求显式重命名。 - fuzz 目标能 panic 却没断言:Skill 提示 fuzz 至少要保证不 panic、不死循环,否则会污染 CI。
- 覆盖率高但分支没覆盖:
go test -cover只看语句,Skill 推荐同时用-covermode=atomic并跑go test -run NONE -coverpkg=./... ./...拿全分支数据。 - mock 写死实现:用
gock/httpmock时别忘了在defer里 reset,Skill 提示统一用t.Cleanup(...)。 - benchmark 之前有 setup 干扰:必须
b.ResetTimer(),否则初始化时间会算进 ns/op,Skill 把这条写进模板。 - 跳过 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/掘金/知乎
推荐资源:
- 官方文档:https://github.com/affaan-m/everything-claude-code
- 官方仓库 README 里的 Examples
- 社区最佳实践:Anthropic 官方博客 https://www.anthropic.com/blog
- 国内社区:CSDN AI 板块、掘金 AI 板块
避免的坑:
- 不要装太多 Skill(超过 10 个会拖慢 Agent)
- 不要把 Skill 装在不兼容的 Agent 上
- 不要直接复制 Skill 默认 prompt——要根据项目调整
- 定期 review Skill 库的实用性,清理不用的
参考链接
- affaan-m/everything-claude-code 仓库:https://github.com/affaan-m/everything-claude-code
- golang-testing 子目录:https://github.com/affaan-m/everything-claude-code/tree/main/skills/golang-testing
- Go 官方 testing 文档:https://pkg.go.dev/testing
- Go Fuzzing 教程:https://go.dev/security/fuzz/
- testify 库:https://github.com/stretchr/testify
- testcontainers-go:https://golang.testcontainers.org/
- Go 性能基准:https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go
- Go 代码审查 checklist:https://github.com/golang/go/wiki/CodeReviewComments
我的个人推荐(测试编辑 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 表驱动测试(最重要)
// 标准表驱动测试模板
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)
}
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 数据库 | 单元测试数据库 |
| httptest | stdlib 模拟 HTTP | HTTP 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
- 标准库
encoding/json整数解析 - 标准库
net/url解析边界 - 多个流行 Go 库的 panic
7.3 fuzztime 建议
| 阶段 | fuzztime | 目的 |
|---|---|---|
| PR 检查 | 5s | 快速 smoke test |
| Nightly | 5min | 深度找 bug |
| Weekly | 1h | 压力测试 |
| Release 前 | 24h | 全面验证 |
八、与其他 Skill 配合
| Skill | 配合方式 |
|---|---|
| golang-patterns | 写测试前的代码模式 |
| superpowers/test-driven-development | TDD 方法论 |
| 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% |
| 线上 bug | 20/月 | 3/月 | -85% |
| 测试运行时间 | 10min | 2min | -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 行)
参考链接:
快速安装
git clone https://github.com/affaan-m/everything-claude-code.git
cd everything-claude-code
ls skills/golang-testing