go-testing

Go Testing Core Knowledge

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "go-testing" with this command: npx skills add claude-dev-suite/claude-dev-suite/claude-dev-suite-claude-dev-suite-go-testing

Go Testing Core Knowledge

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: go for comprehensive documentation.

Full Reference: See advanced.md for HTTP Testing, Benchmarks, Test Helpers, Test Fixtures, Integration Tests, Parallel Tests, and Test Coverage.

When NOT to Use This Skill

  • JavaScript/TypeScript Projects - Use vitest or jest

  • Java Projects - Use junit for Java testing

  • Python Projects - Use pytest for Python

  • E2E Browser Testing - Use Playwright or Selenium

  • Rust Projects - Use rust-testing skill

Basic Testing

Unit Tests

// math.go package math

func Add(a, b int) int { return a + b }

func Divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil }

// math_test.go package math

import "testing"

func TestAdd(t *testing.T) { result := Add(2, 3) if result != 5 { t.Errorf("Add(2, 3) = %d; want 5", result) } }

func TestDivide(t *testing.T) { result, err := Divide(10, 2) if err != nil { t.Fatalf("unexpected error: %v", err) } if result != 5.0 { t.Errorf("Divide(10, 2) = %f; want 5.0", result) } }

func TestDivideByZero(t *testing.T) { _, err := Divide(10, 0) if err == nil { t.Error("expected error for division by zero") } }

Running Tests

Run all tests

go test ./...

Run tests in current package

go test

Run specific test

go test -run TestAdd

Verbose output

go test -v

Run with coverage

go test -cover

Generate coverage report

go test -coverprofile=coverage.out go tool cover -html=coverage.out

Run tests with race detector

go test -race

Set timeout

go test -timeout 30s

Table-Driven Tests

func TestAddTableDriven(t *testing.T) { tests := []struct { name string a, b int expected int }{ {"positive numbers", 2, 3, 5}, {"negative numbers", -1, -1, -2}, {"zero", 0, 0, 0}, {"mixed", -1, 1, 0}, }

for _, tt := range tests {
    t.Run(tt.name, func(t *testing.T) {
        result := Add(tt.a, tt.b)
        if result != tt.expected {
            t.Errorf("Add(%d, %d) = %d; want %d",
                tt.a, tt.b, result, tt.expected)
        }
    })
}

}

func TestDivideTableDriven(t *testing.T) { tests := []struct { name string a, b float64 expected float64 expectErr bool }{ {"normal division", 10, 2, 5, false}, {"division by zero", 10, 0, 0, true}, {"negative result", -10, 2, -5, false}, }

for _, tt := range tests {
    t.Run(tt.name, func(t *testing.T) {
        result, err := Divide(tt.a, tt.b)

        if tt.expectErr {
            if err == nil {
                t.Error("expected error, got nil")
            }
            return
        }

        if err != nil {
            t.Fatalf("unexpected error: %v", err)
        }
        if result != tt.expected {
            t.Errorf("got %f; want %f", result, tt.expected)
        }
    })
}

}

Testify

go get github.com/stretchr/testify

Assert Package

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

func TestWithAssert(t *testing.T) { // Equality assert.Equal(t, 5, Add(2, 3)) assert.NotEqual(t, 6, Add(2, 3))

// Boolean
assert.True(t, true)
assert.False(t, false)

// Nil checks
assert.Nil(t, nil)
assert.NotNil(t, "value")

// Error checks
_, err := Divide(10, 0)
assert.Error(t, err)
assert.EqualError(t, err, "division by zero")

result, err := Divide(10, 2)
assert.NoError(t, err)
assert.Equal(t, 5.0, result)

// Contains
assert.Contains(t, "hello world", "world")
assert.Contains(t, []int{1, 2, 3}, 2)

// Length
assert.Len(t, []int{1, 2, 3}, 3)

// Panics
assert.Panics(t, func() { panic("boom") })

}

Require Package

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

func TestWithRequire(t *testing.T) { // require stops test on failure (unlike assert) result, err := Divide(10, 2) require.NoError(t, err) // Test stops here if err != nil require.Equal(t, 5.0, result) }

Suite Package

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

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

func (s *UserServiceTestSuite) SetupSuite() { // Run once before all tests var err error s.db, err = sql.Open("postgres", "test-connection") s.Require().NoError(err) }

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

func (s *UserServiceTestSuite) SetupTest() { // Run before each test s.service = NewUserService(s.db) }

func (s *UserServiceTestSuite) TearDownTest() { // Run after each test s.db.Exec("DELETE FROM users") }

func (s *UserServiceTestSuite) TestCreateUser() { user, err := s.service.Create("alice", "alice@example.com") s.Require().NoError(err) s.Assert().Equal("alice", user.Name) s.Assert().NotZero(user.ID) }

func TestUserServiceSuite(t *testing.T) { suite.Run(t, new(UserServiceTestSuite)) }

Mocking with gomock

go install go.uber.org/mock/mockgen@latest

Generate Mocks

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

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

Generate mocks

go generate ./...

Using Mocks

import ( "testing" "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock" "myapp/mocks" )

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

mockRepo := mocks.NewMockUserRepository(ctrl)

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

// Create service with mock
service := NewUserService(mockRepo)

// Test
user, err := service.GetUser("1")
assert.NoError(t, err)
assert.Equal(t, "Alice", user.Name)

}

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

mockRepo := mocks.NewMockUserRepository(ctrl)

// Match any user with specific name
mockRepo.EXPECT().
    Create(gomock.Any()).
    DoAndReturn(func(u *User) error {
        u.ID = "generated-id"
        return nil
    }).
    Times(1)

service := NewUserService(mockRepo)
user, err := service.CreateUser("Bob", "bob@example.com")

assert.NoError(t, err)
assert.Equal(t, "generated-id", user.ID)

}

gomock Matchers

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

mock := mocks.NewMockUserRepository(ctrl)

// Any value
mock.EXPECT().Get(gomock.Any()).Return(nil, nil)

// Specific value
mock.EXPECT().Get(gomock.Eq("123")).Return(nil, nil)

// Not equal
mock.EXPECT().Get(gomock.Not("")).Return(nil, nil)

// Custom matcher
userWithName := gomock.Cond(func(u interface{}) bool {
    user, ok := u.(*User)
    return ok && user.Name != ""
})
mock.EXPECT().Create(userWithName).Return(nil)

}

Call Order

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

mock := mocks.NewMockUserRepository(ctrl)

// InOrder ensures calls happen in sequence
gomock.InOrder(
    mock.EXPECT().Get("1").Return(&User{ID: "1"}, nil),
    mock.EXPECT().Update(gomock.Any()).Return(nil),
)

// Use mock...

}

Checklist

  • Unit tests for all public functions

  • Table-driven tests for multiple cases

  • testify/assert for cleaner assertions

  • Mock external dependencies

  • HTTP handler tests

  • Benchmarks for performance-critical code

  • Integration tests with build tags

  • Parallel tests where appropriate

  • Coverage reporting in CI

Anti-Patterns

Anti-Pattern Why It's Bad Solution

Not using table-driven tests Duplicate test code Use []struct{} for test cases

Testing unexported functions Coupled to implementation Test through exported API

Not using t.Helper() Confusing error line numbers Mark helper functions with t.Helper()

Sharing test state Flaky, order-dependent Isolate setup in each test

Not using subtests All cases fail if one fails Use t.Run() for subtests

Ignoring race detector Hidden concurrency bugs Run tests with -race flag

Not benchmarking Performance regressions Add benchmarks for critical paths

Quick Troubleshooting

Problem Likely Cause Solution

"No tests found" Wrong file naming Use *_test.go naming

Race condition detected Shared mutable state Fix data races, use sync primitives

Mock not called Wrong method or args Check gomock expectations

Coverage not accurate Missing test files Run go test ./... for all packages

Test timeout Infinite loop or slow operation Add -timeout flag, investigate

"interface conversion" panic Wrong mock interface Ensure mock implements correct interface

Reference Documentation

  • Unit Tests

  • Testify

  • Mocking

  • Advanced Patterns

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

cron-scheduling

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

token-optimization

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

webrtc

No summary provided by upstream source.

Repository SourceNeeds Review