Skip to content

What it is

Testify adds assertions, mocks and test suites on top of Go's standard testing package, and is the most widely used Go testing library.

assert reports a failure and continues; require reports and stops. mock provides call recording and expectations; suite adds setup and teardown hooks around grouped tests.

Installation

go get github.com/stretchr/testify

Getting started

The smallest useful thing you can do with it, and what each part means.

assert versus require
func TestGetBook(t *testing.T) {
    book, err := store.Get(ctx, 42)

    // require stops the test — without this, the next line would panic.
    require.NoError(t, err)
    require.NotNil(t, book)

    // assert continues, so one run reports every mismatch.
    assert.Equal(t, "Dune", book.Title)
    assert.Equal(t, 1965, book.Year)
}
The rule of thumb: require for preconditions whose failure makes the rest meaningless, assert for the individual facts you are checking.
Table-driven tests
func TestSlugify(t *testing.T) {
    cases := []struct {
        name, input, want string
    }{
        {"simple", "Hello World", "hello-world"},
        {"punctuation", "C++ & Go!", "c-go"},
        {"empty", "", ""},
    }

    for _, tc := range cases {
        t.Run(tc.name, func(t *testing.T) {
            assert.Equal(t, tc.want, Slugify(tc.input))
        })
    }
}
Table-driven tests are the dominant Go idiom. t.Run gives each case its own name in the output so a failure points at the specific input.

Advanced usage

Where the library earns its place over a simpler alternative.

Mocking an interface
type MockStore struct{ mock.Mock }

func (m *MockStore) Get(ctx context.Context, id int) (*Book, error) {
    args := m.Called(ctx, id)
    if args.Get(0) == nil {
        return nil, args.Error(1)
    }
    return args.Get(0).(*Book), args.Error(1)
}

func TestHandler(t *testing.T) {
    store := new(MockStore)
    store.On("Get", mock.Anything, 42).Return(&Book{Title: "Dune"}, nil)

    handler := NewHandler(store)
    handler.Serve(...)

    store.AssertExpectations(t) // fails if Get was never called
}
AssertExpectations is the part people forget: without it, a mock that was never called still passes silently.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Test panics with a nil dereference after a failed assert
assert continues after failing. Use require for anything the subsequent lines depend on.
mock: I don't know what to return
A method was called with arguments no On() expectation matches. Loosen the matcher with mock.Anything or add the missing expectation.

Best practices

  • Use require for preconditions and assert for the assertions under test.
  • Prefer table-driven tests with t.Run so failures identify the case.
  • Call AssertExpectations on mocks, or the expectations prove nothing.
  • Reach for real dependencies via Testcontainers before mocking a database — mocks of complex systems drift from reality.

Background

Why it exists, and what it was reacting to.

Testify filled the gap left by Go's deliberately minimal testing package, where every check is an if statement and a t.Errorf. Its assert and require packages made test failures readable without abandoning the standard runner.