golang-stretchr-testify

von samber

Umfassender Leitfaden zu stretchr/testify für Golang-Tests. Behandelt die Pakete assert, require, mock und suite ausführlich. Verwenden beim Schreiben von Tests mit testify, Erstellen von Mocks, Einrichten von Test-Suites oder der Wahl zwischen assert und require. Behandelt testify-Assertions, Mock-Erwartungen, Argument-Matcher, Aufrufverifikation, Suite-Lebenszyklus und fortgeschrittene Muster wie Eventually, JSONEq und benutzerdefinierte Matcher. Anwenden, wenn die Codebasis github.com/stretchr/testify importiert.

npx skills add https://github.com/samber/cc-skills-golang --skill golang-stretchr-testify

Persona: You are a Go engineer who treats tests as executable specifications. You write tests to constrain behavior and make failures self-explanatory — not to hit coverage targets.

Modes:

  • Write mode — adding new tests or mocks to a codebase.
  • Review mode — auditing existing test code for testify misuse.

stretchr/testify

testify complements Go's testing package with readable assertions, mocks, and suites. It does not replace testing — always use *testing.T as the entry point.

This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform.

assert vs require

Both offer identical assertions. The difference is failure behavior:

  • assert: records failure, continues — see all failures at once
  • require: calls t.FailNow() — use for preconditions where continuing would panic or mislead

Use assert.New(t) / require.New(t) for readability. Name them is and must:

func TestParseConfig(t *testing.T) {
    is := assert.New(t)
    must := require.New(t)

    cfg, err := ParseConfig("testdata/valid.yaml")
    must.NoError(err)    // stop if parsing fails — cfg would be nil
    must.NotNil(cfg)

    is.Equal("production", cfg.Environment)
    is.Equal(8080, cfg.Port)
    is.True(cfg.TLS.Enabled)
}

Rule: require for preconditions (setup, error checks), assert for verifications. Never mix randomly.

Core Assertions

is := assert.New(t)

// Equality
is.Equal(expected, actual)              // DeepEqual + exact type
is.NotEqual(unexpected, actual)
is.EqualValues(expected, actual)        // converts to common type first
is.EqualExportedValues(expected, actual)

// Nil / Bool / Emptiness
is.Nil(obj)                  is.NotNil(obj)
is.True(cond)                is.False(cond)
is.Empty(collection)         is.NotEmpty(collection)
is.Len(collection, n)

// Contains (strings, slices, map keys)
is.Contains("hello world", "world")
is.Contains([]int{1, 2, 3}, 2)
is.Contains(map[string]int{"a": 1}, "a")

// Comparison
is.Greater(actual, threshold)     is.Less(actual, ceiling)
is.Positive(val)                  is.Negative(val)
is.Zero(val)

// Errors
is.Error(err)                     is.NoError(err)
is.ErrorIs(err, ErrNotFound)      // walks error chain
is.ErrorAs(err, &target)
is.ErrorContains(err, "not found")

// Type
is.IsType(&User{}, obj)
is.Implements((*io.Reader)(nil), obj)

Argument order: always (expected, actual) — swapping produces confusing diff output.

Advanced Assertions

is.ElementsMatch([]string{"b", "a", "c"}, result)             // unordered comparison
is.InDelta(3.14, computedPi, 0.01)                            // float tolerance
is.JSONEq(`{"name":"alice"}`, `{"name": "alice"}`)             // ignores whitespace/key order
is.WithinDuration(expected, actual, 5*time.Second)
is.Regexp(`^user-[a-f0-9]+$`, userID)

// Async polling
is.Eventually(func() bool {
    status, _ := client.GetJobStatus(jobID)
    return status == "completed"
}, 5*time.Second, 100*time.Millisecond)

// Async polling with rich assertions
is.EventuallyWithT(func(c *assert.CollectT) {
    resp, err := client.GetOrder(orderID)
    assert.NoError(c, err)
    assert.Equal(c, "shipped", resp.Status)
}, 10*time.Second, 500*time.Millisecond)

testify/mock

Mock interfaces to isolate the unit under test. Embed mock.Mock, implement methods with m.Called(), always verify with AssertExpectations(t).

Key matchers: mock.Anything, mock.AnythingOfType("T"), mock.MatchedBy(func). Call modifiers: .Once(), .Times(n), .Maybe(), .Run(func).

For defining mocks, argument matchers, call modifiers, return sequences, and verification, see Mock reference.

testify/suite

Suites group related tests with shared setup/teardown.

Lifecycle

SetupSuite()    → once before all tests
  SetupTest()   → before each test
    TestXxx()
  TearDownTest() → after each test
TearDownSuite() → once after all tests

Example

type TokenServiceSuite struct {
    suite.Suite
    store   *MockTokenStore
    service *TokenService
}

func (s *TokenServiceSuite) SetupTest() {
    s.store = new(MockTokenStore)
    s.service = NewTokenService(s.store)
}

func (s *TokenServiceSuite) TestGenerate_ReturnsValidToken() {
    s.store.On("Save", mock.Anything, mock.Anything).Return(nil)
    token, err := s.service.Generate("user-42")
    s.NoError(err)
    s.NotEmpty(token)
    s.store.AssertExpectations(s.T())
}

// Required launcher
func TestTokenServiceSuite(t *testing.T) {
    suite.Run(t, new(TokenServiceSuite))
}

Suite methods like s.Equal() behave like assert. For require: s.Require().NotNil(obj).

Common Mistakes

  • Forgetting AssertExpectations(t) — mock expectations silently pass without verification
  • is.Equal(ErrNotFound, err) — fails on wrapped errors. Use is.ErrorIs to walk the chain
  • Swapped argument order — testify assumes (expected, actual). Swapping produces backwards diffs
  • assert for guards — test continues after failure and panics on nil dereference. Use require
  • Missing suite.Run() — without the launcher function, zero tests execute silently
  • Comparing pointersis.Equal(ptr1, ptr2) compares addresses. Dereference or use EqualExportedValues

Linters

Use testifylint to catch wrong argument order, assert/require misuse, and more. See samber/cc-skills-golang@golang-lint skill.

Cross-References

  • → See samber/cc-skills-golang@golang-testing skill for general test patterns, table-driven tests, and CI
  • → See samber/cc-skills-golang@golang-lint skill for testifylint configuration

Mehr Skills von samber

golang-code-style
samber
Golang code style conventions — line length and breaking, variable declarations, control flow clarity, when comments help vs hurt. Use when writing or reviewing Go code, asking about style or clarity, or establishing project coding standards. Not for naming conventions (→ See `samber/cc-skills-golang@golang-naming` skill), linter configuration (→ See `samber/cc-skills-golang@golang-lint` skill), or doc comments (→ See `samber/cc-skills-golang@golang-documentation` skill).
developmentcode-review
golang-testing
samber
Production-ready Golang tests — table-driven tests, testify suites and mocks, parallel tests, fuzzing, fixtures, goroutine leak detection with goleak, snapshot testing, code coverage, integration tests, idiomatic test naming. Use when writing or reviewing Go tests, choosing a testing approach, setting up Go test CI, or debugging flaky/slow tests. For testify-specific APIs see `samber/cc-skills-golang@golang-stretchr-testify`; for measurement methodology see...
developmenttestingcode-review
golang-design-patterns
samber
Idiomatische Golang-Entwurfsmuster — funktionale Optionen, Konstruktoren, Fehlerfluss und -weitergabe, Ressourcenverwaltung und Lebenszyklus, Graceful Shutdown, Resilienz, Architektur, Dependency Injection, Datenverarbeitung, Streaming und mehr. Anwenden, wenn explizit zwischen Architekturmustern gewählt wird, funktionale Optionen implementiert werden, Konstruktor-APIs entworfen werden, Graceful Shutdown eingerichtet wird, Resilienzmuster angewendet werden oder gefragt wird, welches idiomatische Go-Muster zu einem spezifischen Problem passt.
developmentdesigncode-review
golang-error-handling
samber
Idiomatic Golang error handling — creation, wrapping with %w, errors.Is/As, errors.Join, custom error types, sentinel errors, panic/recover, the single handling rule, structured logging with slog, HTTP request logging middleware, and samber/oops for production errors. Built to make logs usable at scale with log aggregation 3rd-party tools. Apply when creating, wrapping, inspecting, or logging errors in Go code. For samber/oops specifics → See `samber/cc-skills-golang@golang-samber-oops`...
developmentcode-review
golang-performance
samber
Golang-Leistungsoptimierungsmuster und Methodik – bei X-Engpass wird Y angewendet. Behandelt Allokationsreduzierung, CPU-Effizienz, Speicherlayout, GC-Tuning, Pooling, Caching und Hot-Path-Optimierung. Verwenden, wenn Profiling oder Benchmarks einen Engpass identifiziert haben und das richtige Optimierungsmuster zur Behebung benötigt wird. Auch verwenden bei der Durchführung von Performance-Code-Reviews, um Verbesserungen oder Benchmarks vorzuschlagen, die helfen könnten, schnelle Leistungssteigerungen zu identifizieren. Nicht für Messmethodik (→...
developmentcode-review
golang-security
samber
Sicherheitsbest Practices und Schwachstellenprävention für Golang. Behandelt Injection (SQL, Command, XSS), Kryptografie, Dateisystemsicherheit, Netzwerksicherheit, Cookies, Secrets-Management, Speichersicherheit und Logging. Anwenden beim Schreiben, Überprüfen oder Auditieren von Go-Code auf Sicherheit oder bei der Arbeit an risikobehaftetem Code mit Krypto, I/O, Secrets-Management, Benutzereingaben oder Authentifizierung. Enthält Konfiguration von Sicherheitstools.
securitycode-reviewdevelopment
golang-database
samber
Umfassender Leitfaden für Go-Datenbankzugriff — parametrisierte Abfragen, Struct-Scanning, NULL-Spalten, Transaktionen, Isolationsstufen, SELECT FOR UPDATE, Verbindungspool, Batch-Verarbeitung, Kontextweitergabe und Migrationswerkzeuge. Verwenden beim Schreiben, Überprüfen oder Debuggen von Golang-Code, der mit PostgreSQL, MariaDB, MySQL oder SQLite interagiert; für Datenbanktests; oder bei Fragen zu database/sql, sqlx oder pgx. Erzeugt KEINE Datenbankschemata oder Migrations-SQL.
developmentdatabase
golang-lint
samber
Best Practices für Linting und golangci-lint-Konfiguration für Golang-Projekte — Ausführen von Linters, Konfigurieren der .golangci.yml, Unterdrücken von Warnungen mit nolint-Direktiven, Interpretieren von Lint-Ausgaben und Auswählen von Linters. Verwenden bei der Konfiguration von golangci-lint, bei Fragen zu Lint-Warnungen oder nolint-Unterdrückungen, beim Einrichten von Code-Qualitätswerkzeugen oder bei der Auswahl von Linters. Auch verwenden, wenn der Benutzer golangci-lint, go vet, staticcheck oder revive erwähnt.
developmentcode-reviewtesting