Golang / GoLang System Architecture and Testing Interview Questions
What are table-driven tests in Go and why are they the standard testing pattern?
Table-driven tests define all test cases as a slice of structs, then iterate over them with a single test loop. This is Go's idiomatic testing pattern — adopted throughout the standard library. It eliminates duplication, makes adding new cases trivial, and produces clear failure output identifying exactly which case failed.
// Function under test func validateEmail(email string) error { if email == "" { return errors.New("email is required") } if !strings.Contains(email, "@") { return fmt.Errorf("email %q has no @ symbol", email) } return nil } // Table-driven test func TestValidateEmail(t *testing.T) { tests := []struct { name string email string wantErr bool errMsg string // optional: check error message substring }{ { name: "valid email", email: "alice@example.com", wantErr: false, }, { name: "empty email", email: "", wantErr: true, errMsg: "required", }, { name: "missing @ symbol", email: "notanemail", wantErr: true, errMsg: "no @ symbol", }, { name: "@ symbol only", email: "@", wantErr: false, // technically valid by our rule }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validateEmail(tt.email) if (err != nil) != tt.wantErr { t.Errorf("validateEmail(%q): got err = %v, wantErr = %v", tt.email, err, tt.wantErr) return } if tt.wantErr && tt.errMsg != "" { if !strings.Contains(err.Error(), tt.errMsg) { t.Errorf("error %q does not contain %q", err.Error(), tt.errMsg) } } }) } } // Run only a specific subtest: // go test -run TestValidateEmail/empty_email ./...
t.Run benefits: each subtest gets its own scope in test output. Failed subtests show the test name, making debugging immediate. You can run a specific subtest with -run TestFoo/case_name. Parallel subtests are supported with t.Parallel() inside the subtest function.
More Related questions...