askill
go-tdd

go-tddSafety --Repository

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.

0 stars
1.2k downloads
Updated 2/9/2026

Package Files

Loading files...
SKILL.md

When to Use

  • Starting implementation of any new feature (TDD = write test FIRST)
  • Adding tests for existing code
  • Creating mocks for domain ports
  • Setting up integration tests with real databases
  • Writing contract tests between services (producer/consumer)
  • Reviewing test quality

Critical Patterns

PatternRule
Test FIRSTWrite the failing test before writing production code. Always.
Red → Green → RefactorFail → pass → clean up. Never skip a step.
Table-driven testsGo convention: use []struct for test cases
Mocks via interfacesNo mock frameworks needed — domain ports ARE the mock boundary
Test file colocationservice.goservice_test.go in same package
Integration tests taggedUse //go:build integration tag
No test pollutionEach test is independent, no shared mutable state

The TDD Cycle

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

When Writing Code with AI (IMPORTANT)

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

Unit Tests

Table-Driven Pattern

See assets/service_test.go

Mock Pattern (No Framework Needed)

See assets/mock_test.go

Domain Entity Tests

See assets/entity_test.go

Handler Tests (httptest)

See assets/http_test.go


Integration Tests (Testcontainers)

Unit vs Integration

AspectUnit TestIntegration Test
DatabaseIn-memory implementationReal PostgreSQL via testcontainers
External servicesMocked interfacesReal or contract-verified
SpeedMillisecondsSeconds (container startup)
Build tagNone//go:build integration
File suffix_test.go_integration_test.go
When to runAlways (go test ./...)CI + explicit (go test -tags=integration)

Testcontainers Pattern

Every integration test file follows this structure:

  1. Build tag //go:build integration on line 1
  2. TestMain function that starts the container and runs migrations
  3. Shared pool variable for all tests in the package
  4. Table-driven tests using the real pool
  5. Cleanup in TestMain (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.

Repository Test Strategy

Two implementations, two purposes:

LayerImplementationUsed ByWhat It Validates
In-memoryrepository/memory.goUnit tests + local dev without DockerDomain logic, application flow
PostgreSQLrepository/postgres.goIntegration tests (testcontainers) + deployed envsReal SQL, constraints, indexes

See assets/repository_test_strategy.go

See go-repository-pattern skill for in-memory implementation details.


Contract Tests

Contract tests verify that service boundaries (API contracts) don't break silently. Two perspectives:

RoleWhat it testsWho 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

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:

  • JSON serialization/deserialization
  • HTTP status codes for all error paths
  • Request validation (binding tags)
  • Response envelope format ({"data": ...} / {"error": ...})

See assets/handler_integration_test.go for the full handler integration test pattern.


Decision Tree

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

Test Organization

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

Assets

FileDescription
assets/service_test.goTable-driven unit test for application service
assets/mock_test.goManual mock implementation via interfaces
assets/entity_test.goDomain entity unit tests
assets/http_test.goHandler tests with httptest
assets/postgres_setup_test.goTestMain: start PostgreSQL container, run migrations, expose pool
assets/repository_integration_test.goRepository integration tests with real PostgreSQL
assets/repository_test_strategy.goIn-memory vs PostgreSQL test strategy
assets/contract_producer_test.goProducer contract test: verify API response shape
assets/contract_consumer_test.goConsumer contract test: parse responses from other services
assets/handler_integration_test.goFull HTTP handler integration test with httptest
assets/MakefileTest-related Makefile targets

Commands

# 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

Makefile Targets

See assets/Makefile


Anti-Patterns

Don'tDo
Write code first, tests laterWrite test FIRST (red), then code (green)
Use testify/mock or mockgenUse manual mocks via interfaces — simpler, explicit
Test implementation detailsTest behavior — inputs and outputs
Shared state between testsEach test creates its own fixtures
Skip integration testsUse testcontainers — real DB, real behavior
One giant test functionTable-driven tests with descriptive names
t.Log for assertionsUse t.Errorf / t.Fatalf with clear messages
Skip contract tests for APIsValidate response shapes to catch drift early

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

AI review pending.

Metadata

Licenseunknown
Version-
Updated2/9/2026
Publisher333-333-333

Tags

apici-cddatabasegithubtesting