bobmatnyc/claude-mpm-skillsMIT2 files

Golang Testing Strategies

Comprehensive Go testing strategies including table-driven tests, testify assertions, gomock interface mocking, benchmark testing, and CI/CD integration

Specification
Skill ID
bobmatnyc/claude-mpm-skills/golang-testing-strategies
Publisher
bobmatnyc
Repository
claude-mpm-skills
Installs
0
Files
2
License
MIT
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

bobmatnyc/claude-mpm-skills/golang-testing-strategiesInstalls these files
  • SKILL.md
  • metadata.json

What this skill tells the agent

Go Testing Strategies

Overview

Go provides a robust built-in testing framework (testing package) that emphasizes simplicity and developer productivity. Combined with community tools like testify and gomock, Go testing enables comprehensive test coverage with minimal boilerplate.

Key Features:

  • 📋 Table-Driven Tests: Idiomatic pattern for testing multiple inputs
  • ✅ Testify: Readable assertions and test suites
  • 🎭 Gomock: Type-safe interface mocking
  • ⚡ Benchmarking: Built-in performance testing
  • 🔍 Race Detector: Concurrent code safety verification
  • 📊 Coverage: Native coverage reporting and enforcement
  • 🚀 CI Integration: Test caching and parallel execution

When to Use This Skill

Activate this skill when:

  • Writing test suites for Go libraries or applications
  • Setting up testing infrastructure for new projects
  • Mocking external dependencies (databases, APIs, services)
  • Benchmarking performance-critical code paths
  • Ensuring thread-safe concurrent implementations
  • Integrating tests into CI/CD pipelines
  • Migrating from other testing frameworks

Core Testing Principles

The Go Testing Philosophy

  1. Simplicity Over Magic: Use standard library when possible
  2. Table-Driven Tests: Test multiple scenarios with single function
  3. Subtests: Organize related tests with t.Run()
  4. Interface-Based Mocking: Mock dependencies through interfaces
  5. Test Files Colocate: Place *_test.go files alongside code
  6. Package Naming: Use package_test for external tests, package for internal

Test Organization

File Naming Convention:

  • Unit tests: file_test.go
  • Integration tests: file_integration_test.go
  • Benchmark tests: Prefix with Benchmark in same test file

Package Structure:

mypackage/
├── user.go
├── user_test.go              // Internal tests (same package)
├── user_external_test.go     // External tests (package mypackage_test)
├── integration_test.go       // Integration tests
└── testdata/                 // Test fixtures (ignored by go build)
    └── golden.json

Table-Driven Test Pattern

Basic Structure

The idiomatic Go testing pattern for testing multiple inputs:

func TestUserValidation(t *testing.T) {
    tests := []struct {
        name    string
        input   User
        wantErr bool
        errMsg  string
    }{
        {
            name:    "valid user",
            input:   User{Name: "Alice", Age: 30, Email: "alice@example.com"},
            wantErr: false,
        },
        {
            name:    "empty name",
            input:   User{Name: "", Age: 30, Email: "alice@example.com"},
            wantErr: true,
            errMsg:  "name is required",
        },
        {
            name:    "invalid email",
            input:   User{Name: "Bob", Age: 25, Email: "invalid"},
            wantErr: true,
            errMsg:  "invalid email format",
        },
        {
            name:    "negative age",
            input:   User{Name: "Charlie", Age: -5, Email: "charlie@example.com"},
            wantErr: true,
            errMsg:  "age must be positive",
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            err := ValidateUser(tt.input)

            if (err != nil) != tt.wantErr {
                t.Errorf("ValidateUser() error = %v, wantErr %v", err, tt.wantErr)
                return
            }

            if tt.wantErr && err.Error() != tt.errMsg {
                t.Errorf("ValidateUser() error message = %v, want %v", err.Error(), tt.errMsg)
            }
        })
    }
}

Parallel Test Execution

Enable parallel test execution for independent tests:

func TestConcurrentOperations(t *testing.T) {
    tests := []struct {
        name string
        fn   func() int
        want int
    }{
        {"operation 1", func() int { return compute1() }, 42},
        {"operation 2", func() int { return compute2() }, 84},
        {"operation 3", func() int { return compute3() }, 126},
    }

    for _, tt := range tests {
        tt := tt // Capture range variable
        t.Run(tt.name, func(t *testing.T) {
            t.Parallel() // Run tests concurrently

            got := tt.fn()
            if got != tt.want {
                t.Errorf("got %v, want %v", got, tt.want)
            }
        })
    }
}

Testify Framework

Installation

go get github.com/stretchr/testify

Assertions

Replace verbose error checking with readable assertions:

import (
    "testing"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
)

func TestCalculator(t *testing.T) {
    calc := NewCalculator()

    // assert: Test continues on failure
    assert.Equal(t, 5, calc.Add(2, 3))
    assert.NotNil(t, calc)
    assert.True(t, calc.IsReady())

    // require: Test stops on failure (for critical assertions)
    result, err := calc.Divide(10, 2)
    require.NoError(t, err) // Stop if error occurs
    assert.Equal(t, 5, result)
}

func TestUserOperations(t *testing.T) {
    user := &User{ID: 1, Name: "Alice", Email: "alice@example.com"}

    // Object matching
    assert.Equal(t, 1, user.ID)
    assert.Contains(t, user.Email, "@")
    assert.Len(t, user.Name, 5)

    // Partial matching
    assert.ObjectsAreEqual(user, &User{
        ID:    1,
        Name:  "Alice",
        Email: assert.AnythingOfType("string"),
    })
}

Test Suites

Organize related tests with setup/teardown:

import (
    "testing"
    "github.com/stretchr/testify/suite"
)

type UserServiceTestSuite struct {
    suite.Suite
    db      *sql.DB
    service *UserService
}

// SetupSuite runs once before all tests
func (s *UserServiceTestSuite) SetupSuite() {
    s.db = setupTestDatabase()
    s.service = NewUserService(s.db)
}

// TearDownSuite runs once after all tests
func (s *UserServiceTestSuite) TearDownSuite() {
    s.db.Close()
}

// SetupTest runs before each test
func (s *UserServiceTestSuite) SetupTest() {
    cleanDatabase(s.db)
}

// TearDownTest runs after each test
func (s *UserServiceTestSuite) TearDownTest() {
    // Cleanup if needed
}

// Test methods must start with "Test"
func (s *UserServiceTestSuite) TestCreateUser() {
    user := &User{Name: "Alice", Email: "alice@example.com"}

    err := s.service.Create(user)
    s.NoError(err)
    s.NotEqual(0, user.ID) // ID assigned
}

func (s *UserServiceTestSuite) TestGetUser() {
    // Setup
    user := &User{Name: "Bob", Email: "bob@example.com"}
    s.service.Create(user)

    // Test
    retrieved, err := s.service.GetByID(user.ID)
    s.NoError(err)
    s.Equal(user.Name, retrieved.Name)
}

// Run the suite
func TestUserServiceTestSuite(t *testing.T) {
    suite.Run(t, new(UserServiceTestSuite))
}

Gomock Interface Mocking

Installation

go install github.com/golang/mock/mockgen@latest

Generate Mocks

// user_repository.go
package repository

//go:generate mockgen -source=user_repository.go -destination=mocks/mock_user_repository.go -package=mocks

type UserRepository interface {
    GetByID(id int) (*User, error)
    Create(user *User) error
    Update(user *User) error
    Delete(id int) error
}

Generate mocks:

go generate ./...
# Or manually:
mockgen -source=user_repository.go -destination=mocks/mock_user_repository.go -package=mocks

Using Mocks in Tests

import (
    "testing"
    "github.com/golang/mock/gomock"
    "github.com/stretchr/testify/assert"
    "myapp/repository/mocks"
)

func TestUserService_GetUser(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    // Create mock
    mockRepo := mocks.NewMockUserRepository(ctrl)

    // Set expectations
    expectedUser := &User{ID: 1, Name: "Alice"}
    mockRepo.EXPECT().
        GetByID(1).
        Return(expectedUser, nil).
        Times(1)

    // Test
    service := NewUserService(mockRepo)

Use this skill in a project

Open any RiverX project, search the Skills panel for bobmatnyc/claude-mpm-skills/golang-testing-strategies, and install it in one click.

Use this skill