--- description: Enforce TDD workflow for Go. Write table-driven tests first, then implement. Verify 80%+ coverage with go test -cover. --- # Go TDD Command This command enforces test-driven development methodology for Go code using idiomatic Go testing patterns. ## What This Command Does 1. **Define Types/Interfaces**: Scaffold function signatures first 2. **Write Table-Driven Tests**: Create comprehensive test cases (RED) 3. **Run Tests**: Verify tests fail for the right reason 4. **Implement Code**: Write minimal code to pass (GREEN) 5. **Refactor**: Improve while keeping tests green 6. **Check Coverage**: Ensure 80%+ coverage ## When to Use Use `/go-test` when: - Implementing new Go functions - Adding test coverage to existing code - Fixing bugs (write failing test first) - Building critical business logic - Learning TDD workflow in Go ## TDD Cycle ``` RED → Write failing table-driven test GREEN → Implement minimal code to pass REFACTOR → Improve code, tests stay green REPEAT → Next test case ``` ## Example Session ```` User: /go-test I need a function to validate email addresses Agent: # TDD Session: Email Validator ## Step 1: Define Interface ```go // validator/email.go package validator // ValidateEmail checks if the given string is a valid email address. // Returns nil if valid, error describing the issue otherwise. func ValidateEmail(email string) error { panic("not implemented") } ``` ## Step 2: Write Table-Driven Tests (RED) ```go // validator/email_test.go package validator import ( "testing" ) func TestValidateEmail(t *testing.T) { tests := []struct { name string email string wantErr bool }{ // Valid emails {"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}, // Invalid emails {"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) } }) } } ``` ## Step 3: Run Tests - Verify FAIL ```bash $ go test ./validator/... --- FAIL: TestValidateEmail (0.00s) --- FAIL: TestValidateEmail/simple_email (0.00s) panic: not implemented FAIL ``` ✓ Tests fail as expected (panic). ## Step 4: Implement Minimal Code (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 } ``` ## Step 5: Run Tests - Verify PASS ```bash $ go test ./validator/... PASS ok project/validator 0.003s ``` ✓ All tests passing! ## Step 6: Check Coverage ```bash $ go test -cover ./validator/... PASS coverage: 100.0% of statements ok project/validator 0.003s ``` ✓ Coverage: 100% ## TDD Complete! ```` ## Test Patterns ### 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) // assertions }) } ``` ### Parallel Tests ```go for _, tt := range tests { tt := tt // Capture t.Run(tt.name, func(t *testing.T) { t.Parallel() // test body }) } ``` ### Test Helpers ```go func setupTestDB(t *testing.T) *sql.DB { t.Helper() db := createDB() t.Cleanup(func() { db.Close() }) return db } ``` ## Coverage Commands ```bash # Basic coverage go test -cover ./... # Coverage profile go test -coverprofile=coverage.out ./... # View in browser go tool cover -html=coverage.out # Coverage by function go tool cover -func=coverage.out # With race detection go test -race -cover ./... ``` ## Coverage Targets | Code Type | Target | |-----------|--------| | Critical business logic | 100% | | Public APIs | 90%+ | | General code | 80%+ | | Generated code | Exclude | ## TDD Best Practices **DO:** - Write test FIRST, before any implementation - Run tests after each change - Use table-driven tests for comprehensive coverage - Test behavior, not implementation details - Include edge cases (empty, nil, max values) **DON'T:** - Write implementation before tests - Skip the RED phase - Test private functions directly - Use `time.Sleep` in tests - Ignore flaky tests ## Related Commands - `/go-build` - Fix build errors - `/go-review` - Review code after implementation - `/verify` - Run full verification loop ## Related - Skill: `skills/golang-testing/` - Skill: `skills/tdd-workflow/`