A table-driven test represents many test scenarios as data, then runs one shared procedure against every row. In Go, this idiom separates inputs and expected results from assertion logic, reducing repeated test code while making new cases easy to add. section 2.4
A test table is commonly a slice of anonymous structs. Give each row a descriptive name, the input to pass to the function, and the expected result. Keeping the table in test code allows multiple tests to reuse the scenarios without placing test-only data in production builds. section 2.4.1
Listing 2.7 A table-driven test case (url/url_test.go)
var parseTests = []struct { #1
name string #1
uri string #1
want *URL #1
}{
{ #2
name: "full", #2
uri: "https://github.com/inancgumus", #2
want: &URL{ #2
Scheme: "https", #2
Host: "github.com", #2
Path: "inancgumus", #2
}, #2
}, #2
{ #3
name: "without_path", #3
uri: "https://github.com", #3
want: &URL{ #3
Scheme: "https", #3
Host: "github.com", #3
Path: "", #3
}, #3
}, #3
/* many more test cases can be easily added */ #3
} #3
This test-case table names URL parsing scenarios and pairs each URI with the URL value expected from Parse. section 2.4.1
Build a table-driven test in a direct loop:
- Define a row type with fields for a case name, input, and expected output. section 2.4.1
- Populate a slice with representative scenarios, including cases discovered when fixing bugs. section 2.4.1
- Range over the slice, call the function with each row’s input, and compare got with want. section 2.4.2
- Log the case name so a failing run identifies the scenario being exercised. section 2.4.2
Testing URL parsing
A Parse test can store full and pathless URLs in parseTests. For each row, it calls Parse(tt.uri), treats an unexpected error as fatal, and compares the returned URL with tt.want. The same test logic therefore checks every listed URL shape. section 2.4.1 section 2.4.2
Listing 2.8 A table-driven test (url/url_test.go)
func TestParseTable(t *testing.T) { for _, tt := range parseTests { #1 t.Logf("run %s", tt.name) #2 got, err := Parse(tt.uri) #3 if err != nil { #3 t.Fatalf( #3 "Parse(%q) err = %v, want <nil>", #3 tt.uri, err, #3 ) #3 } #3 if *got != *tt.want { #3 t.Errorf( #3 "Parse(%q)\ngot %#v\nwant %#v", #3 tt.uri, got, tt.want, #3 ) } } }
The loop shows the core arrangement: retrieve each row, run Parse with its input, and report differences between got and want. section 2.4.2
Consolidation has a trade-off: all rows run inside one test function. A call to Fatalf for an early row ends that function and skips later cases, and a run filter cannot select an individual row. Use subtests when each case needs independent failure isolation or selective execution. section 2.4.4 section 2.5.1
Run a focused table test with go test and the -run flag, using an anchored pattern when needed. This targets the test function, not a particular table row; subtests extend the approach by giving rows separately runnable names. section 2.4.3 section 2.5.1





