Go HTTP response test helper

Simplify handler testing by introducing test helpers. Focus on quality error messages. This design takes inspiration from Bertrand Meyers, Design by Contract


package example

// ... imports hidden for brevity ...

func Test_helloWorld(t *testing.T) {
	// require
	h := helloWorld()
	r := httptest.NewRequest("GET", "/", http.NoBody)

	// do
	resp := recordResp(h, r)
	data := readBody(resp)

	// ensure
	ensure(t,
		statusCodeIs(resp.StatusCode, 201),
		bodyContains(data, "Hello", "space"),
	)
}

References: http/httptest, testing and helloWorld

Compile and test your code

$ go test .
--- FAIL: Test_helloWorld (0.00s)
    helloworld_test.go:21: status code 200, expected 201
    helloworld_test.go:21: body missing ["space"]

func recordResp(h http.Handler, r *http.Request) *http.Response {
	w := httptest.NewRecorder()
	h.ServeHTTP(w, r)
	return w.Result()
}

func readBody(resp *http.Response) string {
	data, _ := ioutil.ReadAll(resp.Body)
	return string(data)
}

func ensure(t *testing.T, errors ...error) {
	t.Helper()
	for _, err := range errors {
		if err != nil {
			t.Error(err)
		}
	}
}

func statusCodeIs(got, exp int) error {
	if err := equals(got, exp); err != nil {
		return fmt.Errorf("status code %w", err)
	}
	return nil
}

func bodyContains(body string, phrases ...string) error {
	if err := contains(body, phrases...); err != nil {
		return fmt.Errorf("body %w", err)
	}
	return nil
}


func equals[T comparable](got, exp T) error {
	if got != exp {
		return fmt.Errorf("%v, expected %v", got, exp)
	}
	return nil
}

func contains(got string, expect ...string) error {
	var miss []string
	for _, exp := range expect {
		if !strings.Contains(got, exp) {
			miss = append(miss, exp)
		}
	}
	if len(miss) > 0 {
		return fmt.Errorf("missing %q", miss)
	}
	return nil
}