Table-driven tests — catching the lesson-7 bug
One input per test is thin. Real functions need checking against several cases — normal, edge, tricky. Writing a separate Test… for each is noise. The Go idiom is a table-driven test: a slice of {input, want} rows, and one loop that checks them all.
Recall charCount from lesson 7 — it returns how many characters are in a string. Here's a table test for it:
func TestCharCount(t *testing.T) {
cases := []struct {
in string
want int
}{
{"obuolys", 7},
{"ąžuolas", 7}, // Lithuanian: 7 characters, but 9 bytes
{"Go", 2},
{"", 0},
}
for _, c := range cases {
got := charCount(c.in)
if got != c.want {
t.Errorf("charCount(%q) = %d, want %d", c.in, got, c.want)
}
}
}
The cases := []struct{…}{…} is an anonymous struct slice — a throwaway type that exists just to list the rows. Each row is one case; the loop runs them all and reports every mismatch independently. Adding a new case is one line, not a new function.
Now the spine — this test is a trap set for a real bug. Remember lesson 7: the naive way to count characters is len(s), and it's wrong for Lithuanian, because len counts bytes and "ą" is 2 bytes. Suppose charCount still had the bug:
func charCount(s string) int {
return len(s) // BUG: counts BYTES, not characters
}
Run go test:
--- FAIL: TestCharCount (0.00s)
text_test.go:18: charCount("ąžuolas") = 9, want 7
FAIL
FAIL yourapp 1.7s
There it is. The machine caught it — = 9, want 7 — the exact bug, named, before any user ever typed a Lithuanian title. No staring at output, no guessing: the failing line points straight at the case that broke.
Now fix charCount the way lesson 7 taught:
import "unicode/utf8"
func charCount(s string) int {
return utf8.RuneCountInString(s) // counts CHARACTERS
}
Run go test again:
ok yourapp 0.5s
And with -v you see it pass by name:
=== RUN TestCharCount
--- PASS: TestCharCount (0.00s)
PASS
That's the whole point of testing. The bug from lesson 7 used to hide until a specific input hit it in production. Now a test remembers it forever: if anyone ever "simplifies" charCount back to len, the test goes red on the next run. A test is a bug you only have to catch once.
Next: write the full test file for your app — charCount, truncateRunes and validateTitle, all in one _test.go.