A table-driven test represents multiple cases as data records and runs one validation procedure over them. It replaces repeated test code with a struct, a slice, and a loop. section 8.5.5
Build the test around the values that vary:
- Define a test-case struct containing every input and expected result needed for one iteration. section 8.5.5
- Create a slice whose records represent individual cases, grouped together at the start of the test. section 8.5.5
- Loop over the slice, execute the shared procedure, log the case values, and compare actual results with expectations. section 8.5.5
- Add or remove scenarios by changing data records instead of duplicating testing logic. section 8.5.5
Calculator permutations
A Calculate test stores the operation, two operands, and expected result in each record, then checks division, addition, multiplication, and subtraction through one loop. When an operation returns an error, the test reports it and continues to the next case.
Listing 8.30 handler_test.go: Table test for handlers
func TestHandler(t *testing.T) {
// Arrange
tt := []struct { #1
Handler http.HandlerFunc
Action string
Body []byte
StatusCode int
ExpectedResponse string
}{
{
Handler: hello.HelloGet,
Action: "GET",
StatusCode: http.StatusOK,
Body: nil,
ExpectedResponse: "hello",
},
{
Handler: hello.HelloPost,
Action: "POST",
StatusCode: http.StatusCreated,
Body: []byte("Go in Action"),
ExpectedResponse: "hello Go in Action",
},
}
for _, test := range tt { #2
handler := http.HandlerFunc(test.Handler)
rr := httptest.NewRecorder()
req, err := http.NewRequest(
test.Action, "", bytes.NewBuffer(test.Body))
if err != nil {
t.Errorf("unable to create request %s", err)
t.FailNow()
}
// Act
handler.ServeHTTP(rr, req)
// Assert
if rr.Code != test.StatusCode {
t.Errorf(`expected status %d but received %d`,
test.StatusCode, rr.Code)
}
respBody, err := io.ReadAll(rr.Body)
if err != nil {
t.Errorf("unable to read response %s", err)
t.FailNow()
}
if string(respBody) != test.ExpectedResponse {
t.Errorf("expected '%s' received '%s'",
test.ExpectedResponse, string(respBody))
t.Fail()
}
}
}
Inspect a handler table that varies HTTP method, request body, expected status, and response while reusing the same request-and-assert procedure. section 8.6





