skills/go-tdd/SKILL.md
Test-Driven Development workflow in Go: red-green-refactor cycle, table-driven tests, mocks via interfaces, integration tests with testcontainers, and contract tests between services. Trigger: When writing tests, implementing TDD, creating mocks, setting up integration tests, or creating contract tests.
npx skillsauth add 333-333-333/agents go-tddInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Pattern | Rule |
|---------|------|
| Test FIRST | Write the failing test before writing production code. Always. |
| Red → Green → Refactor | Fail → pass → clean up. Never skip a step. |
| Table-driven tests | Go convention: use []struct for test cases |
| Mocks via interfaces | No mock frameworks needed — domain ports ARE the mock boundary |
| Test file colocation | service.go → service_test.go in same package |
| Integration tests tagged | Use //go:build integration tag |
| No test pollution | Each test is independent, no shared mutable state |
1. RED — Write a test that describes the desired behavior. Run it. It MUST fail.
2. GREEN — Write the MINIMUM code to make the test pass. Nothing more.
3. REFACTOR — Clean up the code while keeping tests green.
4. REPEAT
1. DESCRIBE the behavior you want as a test
2. AI writes the failing test
3. Run it — confirm RED
4. AI writes the implementation
5. Run it — confirm GREEN
6. AI refactors if needed
7. Run it — confirm still GREEN
See assets/service_test.go
See assets/mock_test.go
See assets/entity_test.go
See assets/http_test.go
| Aspect | Unit Test | Integration Test |
|--------|-----------|-----------------|
| Database | In-memory implementation | Real PostgreSQL via testcontainers |
| External services | Mocked interfaces | Real or contract-verified |
| Speed | Milliseconds | Seconds (container startup) |
| Build tag | None | //go:build integration |
| File suffix | _test.go | _integration_test.go |
| When to run | Always (go test ./...) | CI + explicit (go test -tags=integration) |
Every integration test file follows this structure:
//go:build integration on line 1TestMain function that starts the container and runs migrationspool variable for all tests in the packageTestMain (container terminates automatically)See assets/postgres_setup_test.go for the TestMain pattern with PostgreSQL container setup.
See assets/repository_integration_test.go for repository integration test examples.
Two implementations, two purposes:
| Layer | Implementation | Used By | What It Validates |
|-------|---------------|---------|-------------------|
| In-memory | repository/memory.go | Unit tests + local dev without Docker | Domain logic, application flow |
| PostgreSQL | repository/postgres.go | Integration tests (testcontainers) + deployed envs | Real SQL, constraints, indexes |
See assets/repository_test_strategy.go
See
go-repository-patternskill for in-memory implementation details.
Contract tests verify that service boundaries (API contracts) don't break silently. Two perspectives:
| Role | What it tests | Who owns it | |------|--------------|-------------| | Producer | "My API responses match the documented contract" | Service team | | Consumer | "I can parse the response the other service returns" | Client team |
Contract tests run against a real HTTP server (httptest) with in-memory repos — they validate the shape of requests/responses, NOT business logic.
See assets/contract_producer_test.go for producer contract test pattern.
See assets/contract_consumer_test.go for consumer contract test pattern.
Handler integration tests use httptest.NewServer with the real Gin router, real service, and real (or in-memory) repos. They test the full HTTP stack including:
{"data": ...} / {"error": ...})See assets/handler_integration_test.go for the full handler integration test pattern.
Testing domain logic (entity, value object)?
→ Unit test with table-driven pattern
Testing a use case / application service?
→ Unit test with mocked ports (in-memory repo)
Testing a repository method against real SQL?
→ Integration test with testcontainers
Testing a handler's HTTP contract?
→ Contract test with httptest (in-memory repo)
Testing cross-service communication?
→ Consumer contract test (parse expected responses)
Testing migrations work?
→ Integration test: run migrations, verify schema
Testing full HTTP stack (handler → service → repo)?
→ Handler integration test with httptest
internal/booking/
domain/
entity.go
entity_test.go # Unit tests — pure domain logic
port.go
application/
service.go
service_test.go # Unit tests — use cases with in-memory repos
mock_test.go # Mock implementations for non-repo ports
infrastructure/
repository/
memory.go # In-memory implementation
memory_test.go # Unit tests — verify in-memory behavior
postgres.go # PostgreSQL implementation
postgres_integration_test.go # Integration — real DB via testcontainers
handler/
http.go
http_test.go # HTTP handler tests — httptest
http_contract_test.go # Contract tests — response shape validation
| File | Description |
|------|-------------|
| assets/service_test.go | Table-driven unit test for application service |
| assets/mock_test.go | Manual mock implementation via interfaces |
| assets/entity_test.go | Domain entity unit tests |
| assets/http_test.go | Handler tests with httptest |
| assets/postgres_setup_test.go | TestMain: start PostgreSQL container, run migrations, expose pool |
| assets/repository_integration_test.go | Repository integration tests with real PostgreSQL |
| assets/repository_test_strategy.go | In-memory vs PostgreSQL test strategy |
| assets/contract_producer_test.go | Producer contract test: verify API response shape |
| assets/contract_consumer_test.go | Consumer contract test: parse responses from other services |
| assets/handler_integration_test.go | Full HTTP handler integration test with httptest |
| assets/Makefile | Test-related Makefile targets |
# Run all unit tests
go test ./...
# Run with verbose output
go test -v ./...
# Run specific package
go test -v ./internal/booking/application/...
# Run integration tests only
go test -v -tags=integration ./...
# Run with coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run specific test
go test -v -run TestBookingService_CreateBooking ./internal/booking/application/
# Race detection
go test -race ./...
# Testcontainers dependency
go get github.com/testcontainers/testcontainers-go
go get github.com/testcontainers/testcontainers-go/modules/postgres
See assets/Makefile
| Don't | Do |
|----------|-------|
| Write code first, tests later | Write test FIRST (red), then code (green) |
| Use testify/mock or mockgen | Use manual mocks via interfaces — simpler, explicit |
| Test implementation details | Test behavior — inputs and outputs |
| Shared state between tests | Each test creates its own fixtures |
| Skip integration tests | Use testcontainers — real DB, real behavior |
| One giant test function | Table-driven tests with descriptive names |
| t.Log for assertions | Use t.Errorf / t.Fatalf with clear messages |
| Skip contract tests for APIs | Validate response shapes to catch drift early |
testing
Review Flutter components and screens for UX/UI compliance. Trigger: When user invokes /ux-review command or requests UX audit.
development
TypeScript strict patterns and best practices. Trigger: When implementing or refactoring TypeScript in .ts/.tsx (types, interfaces, generics, const maps, type guards, removing any, tightening unknown).
testing
Testing philosophy and strategy for every feature: test pyramid, mandatory levels per change type, completion checklist, and skill delegation. Trigger: When planning tests for a feature, reviewing test coverage, defining acceptance criteria, or asking what tests a change needs.
development
Terraform security practices: sensitive variables, secret management, state protection, .gitignore patterns, and CI/CD credential handling. Trigger: When handling secrets in Terraform, configuring state backends, reviewing .gitignore for Terraform, or setting up CI/CD pipelines for infrastructure.