Files
everything-claude-code-zh/commands/go-test.md

269 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: 强制执行 Go 的测试驱动开发TDD工作流。先编写表驱动测试Table-Driven Tests然后进行实现。使用 go test -cover 验证 80% 以上的覆盖率。
---
# Go TDD 命令
此命令使用地道的 Go 测试模式为 Go 代码强制执行测试驱动开发Test-Driven DevelopmentTDD方法论。
## 此命令的作用
1. **定义类型/接口**:首先搭建函数签名的支架
2. **编写表驱动测试Table-Driven Tests**创建全面的测试用例RED/红灯)
3. **运行测试**:验证测试因预期的原因失败
4. **实现代码**编写通过测试所需的最少代码GREEN/绿灯)
5. **重构Refactor**:在保持测试通过的同时优化代码
6. **检查覆盖率**:确保 80% 以上的覆盖率
## 何时使用
在以下场景使用 `/go-test`
- 实现新的 Go 函数
- 为现有代码增加测试覆盖率
- 修复 Bug先编写失败的测试
- 构建核心业务逻辑
- 在 Go 中学习 TDD 工作流Workflow
## TDD 周期
```
RED红灯 → 编写失败的表驱动测试
GREEN绿灯 → 实现通过测试所需的最少代码
REFACTOR重构 → 优化代码,保持测试通过
REPEAT循环 → 下一个测试用例
```
## 会话示例
```text
User: /go-test 我需要一个验证电子邮件地址的函数
Agent:
# TDD 会话:电子邮件验证器
## 第 1 步:定义接口
```go
// validator/email.go
package validator
// ValidateEmail 检查给定的字符串是否为有效的电子邮件地址。
// 如果有效返回 nil否则返回描述问题的错误。
func ValidateEmail(email string) error {
panic("not implemented")
}
```
## 第 2 步:编写表驱动测试 (RED)
```go
// 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 步:运行测试 - 验证失败
```bash
$ go test ./validator/...
--- FAIL: TestValidateEmail (0.00s)
--- FAIL: TestValidateEmail/simple_email (0.00s)
panic: not implemented
FAIL
```
✓ 测试如预期般失败 (panic)。
## 第 4 步:实现最少代码 (GREEN)
```go
// 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 步:运行测试 - 验证通过
```bash
$ go test ./validator/...
PASS
ok project/validator 0.003s
```
✓ 所有测试通过!
## 第 6 步:检查覆盖率
```bash
$ 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
```go
for _, tt := range tests {
tt := tt // 闭包捕获变量
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
// 测试主体
})
}
```
### 测试助手Test Helpers
```go
func setupTestDB(t *testing.T) *sql.DB {
t.Helper()
db := createDB()
t.Cleanup(func() { db.Close() })
return db
}
```
## 覆盖率命令
```bash
# 基础覆盖率
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/`