liveBook · Manning

Table-driven test

As explained in Learn Go with Pocket-Sized Projects

Table-driven testing is a testing technique that represents multiple input-output scenarios as structured test cases processed by shared test logic.

When several tests call the same function and make the same comparison, keep that logic in one place. A table-driven test stores each input and expected output as a test case, then runs every case through a shared loop. Adding a scenario changes the data, not the assertion code. section 2.3.2

Test several greetings

The named cases cover supported languages, an unsupported language, and an empty input: func TestGreet(t *testing.T) { type testCase struct { lang language want string } tests := map[string]testCase{ "English": {lang: "en", want: "Hello world"}, "French": {lang: "fr", want: "Bonjour le monde"}, "Akkadian, not supported": { lang: "akk", want: `unsupported language: "akk"`, }, "Empty": {lang: "", want: `unsupported language: ""`}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { got := greet(tc.lang) if got != tc.want { t.Errorf("expected: %q, got: %q", tc.want, got) } }) } } Run the test with go test. Each name identifies the scenario whose comparison failed. section 2.3.2 section 2.6

To extend the pattern:

  • Define fields for every input and expected result the shared test needs. A case can also include a wantErr Boolean when an error is part of the expected behavior. section 3.1.4
  • Include success and failure paths. File-loading cases use an existing JSON file, a missing file, and invalid JSON. section 3.1.4
  • Choose a comparison suited to the result. For a slice of structured values, the test can use a comparison helper or reflect.DeepEqual rather than the greeting test’s string comparison. section 3.1.4
  • Keep case data convenient to read. A word-game test stores guesses and solutions as strings, converts them to rune slices when calling computeFeedback, and compares the returned feedback. section 5.2.2

The loop expresses the repeatable work: prepare a case, execute the function, and compare the result with its expectation. Give each case a descriptive name, then add edge cases by adding entries to the table. section 2.3.2 section 2.6 section 5.2.2

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Works through case structs, a map of scenarios, subtests, and comparisons; extends the procedure to errors and structured results.
Examples
Uses multilingual greetings, JSON file-loading outcomes, and word-game feedback to exercise ordinary and edge-case behavior.
What it assumes
Assumes familiarity with calling functions and comparing results while introducing the test-case struct and map-based loop.
What you can do after
Build it from scratch for a Go function, then add named cases without duplicating execution and assertion logic.
How it connects
Connects Go structs, maps, for-range loops, subtests, error handling, and result comparison.

Also explained in

Compare how 6 books explain table-driven test →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.