CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/go-unit-tests

Go unit testing with the stdlib `testing` package - `func TestXxx(t *testing.T)` convention, the table-driven idiom with `t.Run` subtests, `t.Parallel()`, benchmarks (`BenchmarkXxx` + benchstat), examples (`ExampleXxx`), native fuzzing (`FuzzXxx`, Go 1.18+), coverage (`-cover` / `-coverprofile` + threshold gating), build tags, `t.Helper()` / `t.Cleanup`, and `-race` CI. Includes framework choice (stdlib `testing` is the idiomatic default; Ginkgo BDD for Kubernetes-ecosystem projects via references) and test-authoring conventions (framework detection from go.sum + existing suite files, `_test.go` placement, `t.Errorf` vs `t.Fatalf`). References cover Ginkgo + Gomega and Go mocking (gomock, testify/mock). Use for any Go unit-test task: writing table-driven tests, benchmarks, fuzz targets, coverage gates, or CI wiring.

72

Quality

91%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

go-mocking.mdreferences/

Go mocking - gomock and testify/mock (reference)

Companion reference for go-unit-tests. A test double (per ISTQB Glossary) replaces a real dependency so the subject under test runs in isolation. Use when a unit test reaches a database, HTTP client, file system, or any interface boundary; for tests that do not cross an interface boundary, prefer real objects or simple hand-written stubs without a mocking library.

ToolApproach
go.uber.org/mock (gomock + mockgen)Codegen from interface
github.com/stretchr/testify/mockHand-written stub struct

gomock (go.uber.org/mock)

Install and generate

Per github.com/uber-go/mock:

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

# Source mode: generates from a .go file
mockgen -source=internal/store/store.go \
        -destination=internal/store/mock_store.go \
        -package=store

# Package mode: package + interface names
mockgen github.com/myorg/myapp/internal/store Store,Querier \
        > internal/store/mock_store.go

Add a //go:generate mockgen ... directive so go generate ./... keeps mocks in sync (generated mocks go stale when the interface changes - run it in CI to catch drift). The -typed flag emits type-safe Return/Do/DoAndReturn helpers.

Test with gomock

Per pkg.go.dev/go.uber.org/mock/gomock:

func TestOrderService_Submit(t *testing.T) {
    ctrl := gomock.NewController(t)
    // ctrl.Finish() runs automatically via t.Cleanup when *testing.T is passed.

    mockStore := store.NewMockStore(ctrl)

    mockStore.EXPECT().
        SaveOrder(gomock.Any()).
        Return(nil).
        Times(1)

    svc := NewOrderService(mockStore)
    if err := svc.Submit(Order{ID: "abc"}); err != nil {
        t.Fatalf("unexpected error: %v", err)
    }
}

Matchers, counts, ordering

MatcherBehaviour
gomock.Any()Any argument value
gomock.Eq(v)Deep equality
gomock.Nil() / gomock.Not(m)Nil / negation
gomock.AssignableToTypeOf(v)Type-assignability
gomock.InAnyOrder(s)Slice elements in any order
gomock.Regex(re)String matches regexp
mockStore.EXPECT().FindByID(gomock.Any()).Return(nil, ErrNotFound).Times(2)
mockStore.EXPECT().Ping().MinTimes(1).MaxTimes(3)
mockStore.EXPECT().Metrics().AnyTimes()

gomock.InOrder(
    mockStore.EXPECT().Begin(),
    mockStore.EXPECT().SaveOrder(gomock.Any()).Return(nil),
    mockStore.EXPECT().Commit(),
)

testify/mock (github.com/stretchr/testify)

Per github.com/stretchr/testify and pkg.go.dev/github.com/stretchr/testify/mock - embed mock.Mock and implement the interface by hand:

type MockNotifier struct {
    mock.Mock
}

func (m *MockNotifier) Send(to, body string) error {
    args := m.Called(to, body)
    return args.Error(0)
}

func TestAlertService_Notify(t *testing.T) {
    n := new(MockNotifier)
    n.On("Send", "ops@example.com", mock.Anything).Return(nil)

    svc := NewAlertService(n)
    if err := svc.Notify("ops@example.com", "disk full"); err != nil {
        t.Fatalf("unexpected error: %v", err)
    }

    n.AssertExpectations(t)   // every On(...) expectation was exercised
}

mock.Anythinggomock.Any(). Also: n.AssertCalled(t, "Send", ...) / n.AssertNotCalled(t, "Send").

Choosing between them

Concerngomocktestify/mock
Mock generationmockgen codegenHand-written
Argument matchingRich matcher librarymock.Anything + basic
OrderingInOrder/AfterNot built-in
DependencyTwo packagesOne package

gomock when strict call-order or exhaustive matching matters; testify/mock when the team already uses testify/assert and wants one dependency (hand-written stubs must be updated manually on interface change).

Anti-patterns

Anti-patternWhy it failsFix
Mock every dependencyTests verify mock wiring, not behaviorMock only true isolation boundaries
Forget AssertExpectations (testify)Uncalled On(...) passes silentlyAlways call it at the end
Manual ctrl.Finish() (gomock)Redundant with NewController(t)Remove
AnyTimes() everywhereHides missing invocationsDefault to Times(1) / MinTimes(1)

References

SKILL.md

tile.json