go-test
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
- Define Types/Interfaces: Scaffold function signatures first
- Write Table-Driven Tests: Create comprehensive test cases (RED)
- Run Tests: Verify tests fail for the right reason
- Implement Code: Write minimal code to pass (GREEN)
- Refactor: Improve while keeping tests green
- 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 testGREEN → Implement minimal code to passREFACTOR → Improve code, tests stay greenREPEAT → Next test caseExample Session
User: /go-test I need a function to validate email addresses
Agent:# TDD Session: Email Validator
## Step 1: Define Interface
```go// validator/email.gopackage 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.gopackage 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.gopackage 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/...
PASSok project/validator 0.003s```
✓ All tests passing!
## Step 6: Check Coverage
```bash$ go test -cover ./validator/...
PASScoverage: 100.0% of statementsok project/validator 0.003s```
✓ Coverage: 100%
## TDD Complete!Test Patterns
Table-Driven Tests
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
for _, tt := range tests { tt := tt // Capture t.Run(tt.name, func(t *testing.T) { t.Parallel() // test body })}Test Helpers
func setupTestDB(t *testing.T) *sql.DB { t.Helper() db := createDB() t.Cleanup(func() { db.Close() }) return db}Coverage Commands
# Basic coveragego test -cover ./...
# Coverage profilego test -coverprofile=coverage.out ./...
# View in browsergo tool cover -html=coverage.out
# Coverage by functiongo tool cover -func=coverage.out
# With race detectiongo 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.Sleepin tests - Ignore flaky tests
Related Commands
/go-build- Fix build errors/go-review- Review code after implementationverification-loopskill - Run full verification loop
Related
- Skill:
skills/golang-testing/ - Skill:
skills/tdd-workflow/