mirror of
https://github.com/sweetwisdom/everything-claude-code-zh.git
synced 2026-03-22 14:40:14 +00:00
6.0 KiB
6.0 KiB
description
| description |
|---|
| 强制执行 Go 的测试驱动开发(TDD)工作流。先编写表驱动测试(Table-Driven Tests),然后进行实现。使用 go test -cover 验证 80% 以上的覆盖率。 |
Go TDD 命令
此命令使用地道的 Go 测试模式为 Go 代码强制执行测试驱动开发(Test-Driven Development,TDD)方法论。
此命令的作用
- 定义类型/接口:首先搭建函数签名的支架
- 编写表驱动测试(Table-Driven Tests):创建全面的测试用例(RED/红灯)
- 运行测试:验证测试因预期的原因失败
- 实现代码:编写通过测试所需的最少代码(GREEN/绿灯)
- 重构(Refactor):在保持测试通过的同时优化代码
- 检查覆盖率:确保 80% 以上的覆盖率
何时使用
在以下场景使用 /go-test:
- 实现新的 Go 函数
- 为现有代码增加测试覆盖率
- 修复 Bug(先编写失败的测试)
- 构建核心业务逻辑
- 在 Go 中学习 TDD 工作流(Workflow)
TDD 周期
RED(红灯) → 编写失败的表驱动测试
GREEN(绿灯) → 实现通过测试所需的最少代码
REFACTOR(重构) → 优化代码,保持测试通过
REPEAT(循环) → 下一个测试用例
会话示例
User: /go-test 我需要一个验证电子邮件地址的函数
Agent:
# TDD 会话:电子邮件验证器
## 第 1 步:定义接口
```go
// validator/email.go
package validator
// ValidateEmail 检查给定的字符串是否为有效的电子邮件地址。
// 如果有效返回 nil,否则返回描述问题的错误。
func ValidateEmail(email string) error {
panic("not implemented")
}
第 2 步:编写表驱动测试 (RED)
// validator/email_test.go
package validator
import (
"testing"
)
func TestValidateEmail(t *testing.T) {
tests := []struct {
name string
email string
wantErr bool
}{
// 有效邮箱
{"simple email", "user@example.com", false},
{"with subdomain", "user@mail.example.com", false},
{"with plus", "user+tag@example.com", false},
{"with dots", "first.last@example.com", false},
// 无效邮箱
{"empty string", "", true},
{"no at sign", "userexample.com", true},
{"no domain", "user@", true},
{"no local part", "@example.com", true},
{"double at", "user@@example.com", true},
{"spaces", "user @example.com", true},
{"no tld", "user@example", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateEmail(tt.email)
if tt.wantErr && err == nil {
t.Errorf("ValidateEmail(%q) = nil; want error", tt.email)
}
if !tt.wantErr && err != nil {
t.Errorf("ValidateEmail(%q) = %v; want nil", tt.email, err)
}
})
}
}
第 3 步:运行测试 - 验证失败
$ go test ./validator/...
--- FAIL: TestValidateEmail (0.00s)
--- FAIL: TestValidateEmail/simple_email (0.00s)
panic: not implemented
FAIL
✓ 测试如预期般失败 (panic)。
第 4 步:实现最少代码 (GREEN)
// validator/email.go
package validator
import (
"errors"
"regexp"
)
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
var (
ErrEmailEmpty = errors.New("email cannot be empty")
ErrEmailInvalid = errors.New("email format is invalid")
)
func ValidateEmail(email string) error {
if email == "" {
return ErrEmailEmpty
}
if !emailRegex.MatchString(email) {
return ErrEmailInvalid
}
return nil
}
第 5 步:运行测试 - 验证通过
$ go test ./validator/...
PASS
ok project/validator 0.003s
✓ 所有测试通过!
第 6 步:检查覆盖率
$ go test -cover ./validator/...
PASS
coverage: 100.0% of statements
ok project/validator 0.003s
✓ 覆盖率:100%
TDD 完成!
## 测试模式
### 表驱动测试(Table-Driven Tests)
```go
tests := []struct {
name string
input InputType
want OutputType
wantErr bool
}{
{"case 1", input1, want1, false},
{"case 2", input2, want2, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Function(tt.input)
// 断言逻辑
})
}
并行测试(Parallel Tests)
for _, tt := range tests {
tt := tt // 闭包捕获变量
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
// 测试主体
})
}
测试助手(Test Helpers)
func setupTestDB(t *testing.T) *sql.DB {
t.Helper()
db := createDB()
t.Cleanup(func() { db.Close() })
return db
}
覆盖率命令
# 基础覆盖率
go test -cover ./...
# 生成覆盖率分析文件
go test -coverprofile=coverage.out ./...
# 在浏览器中查看结果
go tool cover -html=coverage.out
# 按函数查看覆盖率
go tool cover -func=coverage.out
# 配合竞态检测运行
go test -race -cover ./...
覆盖率目标
| 代码类型 | 目标 |
|---|---|
| 核心业务逻辑 | 100% |
| 公共 API | 90%+ |
| 通用代码 | 80%+ |
| 生成的代码 | 排除 |
TDD 最佳实践
建议这样做:
- 先写测试,在进行任何实现之前
- 每次修改后都运行测试
- 使用表驱动测试以实现全面的覆盖
- 测试行为,而不是实现细节
- 包含边界情况(空值、nil、最大值)
不要这样做:
- 在测试之前编写实现代码
- 跳过 RED(红灯)阶段
- 直接测试私有函数
- 在测试中使用
time.Sleep - 忽略不稳定的测试(Flaky tests)
相关命令
/go-build- 修复构建错误/go-review- 实现后评审代码/verify- 运行完整验证循环
相关内容
- 技能(Skill):
skills/golang-testing/ - 技能(Skill):
skills/tdd-workflow/