Mile High Gophers
May 2025
Blog post
f-tests as a replacement for table-driver tests in Go
by Aliaksandr Valialkin
var indexTests = []struct {
s []int
v int
want int
}{
{
nil,
0,
-1,
},
{
[]int{},
0,
-1,
},
{
[]int{1, 2, 3},
2,
1,
},
{
[]int{1, 2, 2, 3},
2,
1,
},
{
[]int{1, 2, 3, 2},
2,
1,
},
}
func TestIndex(t *testing.T) {
for _, test := range indexTests {
if got := Index(test.s, test.v); got != test.want {
t.Errorf("Index(%v, %v) = %d, want %d", test.s, test.v, got, test.want)
}
}
}
func TestLogfmtParser(t *testing.T) {
f := func(s, resultExpected string) {
t.Helper()
p := getLogfmtParser()
defer putLogfmtParser(p)
p.parse(s)
result := MarshalFieldsToJSON(nil, p.fields)
if string(result) != resultExpected {
t.Fatalf("unexpected result when parsing [%s]; got\n%s\nwant\n%s\n", s, result, resultExpected)
}
}
f(``, `{}`)
f(`foo=bar`, `{"foo":"bar"}`)
f(`foo="bar=baz x=y"`, `{"foo":"bar=baz x=y"}`)
f(`foo=`, `{"foo":""}`)
f(`foo bar`, `{"foo":"","bar":""}`)
}
go test ./...
for everythinggo test ./... -run="MyTest/my subtest"
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := strings.Index(tc.s, tc.substr) // BREAKPOINT here sucks
if got != tc.want {
t.Fatalf("unexepcted n; got %d; want %d", got, tc.want)
}
}
f(`foo=bar`, `{"foo":"bar"}`)
f(`foo="bar=baz x=y"`, `{"foo":"bar=baz x=y"}`)
f(`foo=`, `{"foo":""}`) // BREAKPOINT here is fine
f(`foo`, `{"foo":""}`)
f := func(arg)...
at topf()
call t.Helper()
f()
t.Helper()
used properly to indicate correct line number on failurepeterlyons.com
bluesky: @peterlyons.com
UPDATE user SET
first_name = "Bob",
last_name = "Roberts",
eye_color = "blue",
shoe_size = 10.5,
tag_line = "Ziggity Zoop"
WHERE id = 777;
UPDATE user SET
tag_line = "Bim Bam Boom"
WHERE id = 777;
NULL
and use it heavily in practicenull
What are the semantics behind the "age" property in each message below?
{"age": 27}
{"age": null}
{"name": "Betty"}
This becomes a problem when interoperating with languages that have an explicit way to have a struct or object value be undefined or unset. Go maps have this property, a key either exists or it does not exist in the map, but a Go struct field always exists. Despite this problem in order to avoid completely unstructured data, gain a modicum of type safety and minimal validation it's generally still recommended to use a struct when writing in Go.