apitest

Test frameworks

Use apitest with Ginkgo and other frameworks, and replace how assertions are made.

TestingT

Expect accepts an apitest.TestingT, the subset of *testing.T that apitest uses:

apitest.TestingT
type TestingT interface {
	Errorf(format string, args ...any)
	Fatal(args ...any)
	Fatalf(format string, args ...any)
}

Anything that implements these three methods can run apitest tests. This one records failures instead of failing, which is how you test your own helpers and assertions:

// recordingT collects failures instead of failing the test. Anything with
// Errorf, Fatal and Fatalf satisfies apitest.TestingT.
type recordingT struct {
	errors []string
}

func (r *recordingT) Errorf(format string, args ...any) {
	r.errors = append(r.errors, fmt.Sprintf(format, args...))
}
func (r *recordingT) Fatal(args ...any) { r.errors = append(r.errors, fmt.Sprint(args...)) }
func (r *recordingT) Fatalf(format string, args ...any) {
	r.errors = append(r.errors, fmt.Sprintf(format, args...))
}

func TestHandler_RejectsAnonymousUsers(t *testing.T) {
	rt := &recordingT{}

	apitest.Handler(newSessionApp()).
		Get("/me").
		Expect(rt).
		Status(http.StatusOK).
		End()

	if len(rt.errors) == 0 {
		t.Fatal("expected the status assertion to fail")
	}
}

Ginkgo

GinkgoT() returns a value that satisfies TestingT and reports failures to Ginkgo:

user_test.go
var _ = Describe("User API", func() {
	var (
		t       GinkgoTInterface
		handler http.Handler
	)

	BeforeEach(func() {
		t = GinkgoT()
		handler = newRouter()
	})

	It("gets a user", func() {
		apitest.Handler(handler).
			Get("/user/1234").
			Expect(t).
			Status(http.StatusOK).
			Body(`{"id": "1234", "name": "jon"}`).
			Cookies(apitest.NewCookie("visited").Value("true").Path("/")).
			End()
	})
})

The suite is bootstrapped in the usual way:

ginkgo_suite_test.go
package ginkgo_test

import (
	"testing"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

func TestUserAPI(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "User API")
}

The apitest repository has a complete Ginkgo example.

Verifiers

apitest makes its assertions through a Verifier. The default, apitest.DefaultVerifier, is based on code from testify and reports failures with t.Errorf.

apitest.Verifier
type Verifier interface {
	Equal(t TestingT, expected, actual any, msgAndArgs ...any) bool
	True(t TestingT, value bool, msgAndArgs ...any) bool
	JSONEq(t TestingT, expected string, actual string, msgAndArgs ...any) bool
	Fail(t TestingT, failureMessage string, msgAndArgs ...any) bool
	NoError(t TestingT, err error, msgAndArgs ...any) bool
}

Verifier replaces it for one test. apitest.NoopVerifier makes no assertions at all, which is useful to capture a response, generate a report, or explore an API without failing:

// records the interaction without failing the test
result := apitest.New().
	Verifier(apitest.NoopVerifier{}).
	Handler(handler).
	Get("/brew").
	Expect(t).
	Status(http.StatusOK).
	End()

t.Logf("status was %d", result.Response.StatusCode)

Implement Verifier to route assertions through another library, or to change how failures are reported. The apitest/mocks package has MockVerifier, whose methods can each be replaced with a function.

On this page