go
42 lines · 7 steps
Table-driven tests in Go
A guarded integer divide paired with a table-driven test that runs each case as its own subtest.
Explained by
highlit
1package calc
2
3import "testing"
4
5func Divide(a, b int) (int, error) {
6 if b == 0 {
7 return 0, errDivByZero
8 }
9 return a / b, nil
10}
11
12var errDivByZero = &divError{}
13
14type divError struct{}
15
16func (*divError) Error() string { return "division by zero" }
17
18func TestDivide(t *testing.T) {
19 tests := []struct {
20 name string
21 a, b int
22 want int
23 wantErr bool
24 }{
25 {"simple", 10, 2, 5, false},
26 {"truncates", 7, 2, 3, false},
27 {"negative", -9, 3, -3, false},
28 {"by zero", 1, 0, 0, true},
29 }
30
31 for _, tt := range tests {
32 t.Run(tt.name, func(t *testing.T) {
33 got, err := Divide(tt.a, tt.b)
34 if (err != nil) != tt.wantErr {
35 t.Fatalf("Divide(%d, %d) error = %v, wantErr %v", tt.a, tt.b, err, tt.wantErr)
36 }
37 if got != tt.want {
38 t.Errorf("Divide(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.want)
39 }
40 })
41 }
42}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Returning a sentinel error value lets callers compare against a known failure rather than parsing strings.
- 2A slice of anonymous structs turns many test cases into one readable, easy-to-extend table.
- 3t.Run gives each case its own named subtest, so failures point straight at the offending input.
Related explainers
ruby
class TemplateInterpolator PLACEHOLDER = /\{\{\s*([\w.]+)\s*\}\}/ def initialize(strict: false)
Interpolating templates with dotted keys in Ruby
regex
string-interpolation
hash-traversal
Intermediate
6 steps
go
package handlers import ( "net/http"
Serving embedded static meta files in Gin
embedding
static assets
http caching
Intermediate
6 steps
go
package config import ( "fmt"
A thread-safe config singleton in Go
singleton
concurrency
environment-variables
Intermediate
7 steps
rust
use std::net::Ipv4Addr; use std::str::FromStr; #[derive(Debug, Clone, Copy)]
Parsing and matching IPv4 CIDR ranges in Rust
bitwise-operations
parsing
error-handling
Intermediate
8 steps
go
package scheduler import ( "container/heap"
A priority job queue with Go's container/heap
priority-queue
heap
interfaces
Intermediate
9 steps
typescript
import { parsePhoneNumberFromString, CountryCode } from 'libphonenumber-js'; export interface NormalizedPhone { e164: string;
Normalizing phone numbers to E.164 in TypeScript
validation
normalization
error-handling
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/table-driven-tests-in-go-explained-go-b61a/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.