funcdriven: use function driven tests instead of table driven tests

i would like to give my wholehearted endorsement to this article: https://itnext.io/f-tests-as-a-replacement-for-table-driven-tests-in-go-8814a8b19e9e.

it advocates to replace the table driven tests like

 1| func TestStringsIndex(t *testing.T) {
 2|   tests := []struct {
 3|     name   string
 4|     s      string
 5|     substr string
 6|     want   int
 7|   }{
 8|     {
 9|       name:   "firstCharMatch",
10|       s:      "foobar",
11|       substr: "foo",
12|       want:   0,
13|     },
14|     {
15|       name:   "middleCharMatch",
16|       s:      "foobar",
17|       substr: "bar",
18|       want:   4,
19|     },
20|     {
21|       name:   "mismatch",
22|       s:      "foobar",
23|       substr: "baz",
24|       want:   -1,
25|     },
26|   }
27| 
28|   for _, tc := range tests {
29|     t.Run(tc.name, func(t *testing.T) {
30|       got := strings.Index(tc.s, tc.substr)
31|       if got != tc.want {
32|         t.Fatalf("unexpected n; got %d; want %d", got, tc.want)
33|       }
34|     })
35|   }
36| }

with function driven tests like

 1| func TestStringsIndex(t *testing.T) {
 2|   f := func(s, substr string, nExpected int) {
 3|     t.Helper()
 4| 
 5|     n := strings.Index(s, substr)
 6|     if n != nExpected {
 7|       t.Fatalf("unexpected n; got %d; want %d", n, nExpected)
 8|     }
 9|   }
10| 
11|   // first char match
12|   f("foobar", "foo", 0)
13| 
14|   // middle char match
15|   f("foobar", "bar", 4)
16| 
17|   // mismatch
18|   f("foobar", "baz", -1)
19| }

in case of error this is what you see in the former case:

> t.Fatalf("unexpected n; got %d; want %d", got, tc.want)
funcdriven_test.go:32: unexpected n; got 3; want 4

in the latter case this is what you see in your editor:

> // middle char match
> f("foobar", "bar", 3)
funcdriven_test.go:15: unexpected n; got 3; want 4

basically the error message points directly to the place where the erroneous data is. makes working with tests super convenient.

i used table driven tests for a long time but i now switched over tho this. i confirm from experience that i find these much easier and more natural to work with.

and when ready for an even bigger leap of faith then use https://pkg.go.dev/github.com/ypsu/efftesting/efft to automate away the manual maintenance of the "want" argument.

i am starting to like writing tests, yay.

Published on 2024-11-18.


Add new comment:

(Adding a new comment or reply requires javascript.)


to the frontpage