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

6.0 KiB
Raw Blame History

description
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循环   → 下一个测试用例

会话示例

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 - 运行完整验证循环

相关内容

  • 技能Skillskills/golang-testing/
  • 技能Skillskills/tdd-workflow/