autogold - automatically update your Go tests
autogold makes go test -update
automatically update your Go tests (golden files and Go values in e.g. foo_test.go
).
~5m introduction available on YouTube:
"It's 2021: you shouldn't have to update Go tests manually"
Automatic golden files
Write in a Go test:
import "github.com/hexops/autogold"
...
autogold.Equal(t, got)
go test -update
will now create/update a testdata/<test name>.golden
file for you automatically.
Automatic inline test updating
Write in a Go test:
want := autogold.Want("my_test", nil)
want.Equal(t, got)
go test -update
will automatically update the autogold.Want("my_test", ...)
call with the Go syntax for whatever value your test got
(complex Go struct, slices, strings, etc.)
Diffs
Anytime your test produces a result that is unexpected, you'll get very nice diffs showing exactly what changed. It does this by converting values at runtime directly to a formatted Go AST, and using the same diffing library the Go language server uses:
--- FAIL: TestEqual (0.08s)
autogold.go:91: mismatch (-want +got):
--- want
+++ got
@@ -1 +1 @@
+&example.Baz{Name: "Jane", Age: 31}
Subtesting
Use table-driven Go subtests? autogold.Want
and go test -update
will automatically find and replace the nil
values for you:
func TestTime(t *testing.T) {
testCases := []struct {
gmt string
loc string
want autogold.Value
}{
{"12:31", "Europe/Zuri", autogold.Want("Europe", nil)},
{"12:31", "America/New_York", autogold.Want("America", nil)},
{"08:08", "Australia/Sydney", autogold.Want("Australia", nil)},
}
for _, tc := range testCases {
t.Run(tc.want.Name(), func(t *testing.T) {
loc, err := time.LoadLocation(tc.loc)
if err != nil {
t.Fatal("could not load location")
}
gmt, _ := time.Parse("15:04", tc.gmt)
got := gmt.In(loc).Format("15:04")
tc.want.Equal(t, got)
})
}
}
It works by finding the relevant autogold.Want("<unique name>", ...)
call below the named TestTime
function, and then replacing the nil
parameter (or anything that was there.)
What are golden files, when should they be used?
Golden files are used by the Go authors for testing the standard library, the gofmt
tool, etc. and are a common pattern in the Go community for snapshot testing. See also "Testing with golden files in Go" - Chris Reeves
Golden files make the most sense when you'd otherwise have to write a complex multi-line string or large Go structure inline in your test, making it hard to read.
In most cases, you should prefer inline snapshots, subtest golden values, or traditional Go tests.
Command line syntax: put -update
at the end
-update
should go at the end of your go test
command, otherwise for some reason stdout will be considered a terminal and color will be turned on for libraries like fatih/color. Example:
go test -count=1 -run TestSomething . -update
valast is used to produce Go syntax at runtime for the Go value you provide. If the default output is not to your liking, you have options:
- Pass a string to autogold: It will be formatted as a Go string for you in the resulting
.golden
file / in Go tests.
- Use your own formatting (JSON, etc.): Make your
got
value of type autogold.Raw("foobar")
, and it will be used as-is for .golden
files (not allowed with inline tests.)
- Exclude unexported fields:
autogold.Equal(t, got, autogold.ExportedOnly())
Backwards compatibility
- As is the case with
gofmt
, different Go versions may produce different formattings (although rare.)
- Minor versions of autogold (e.g.
v1.0
, v1.1
) may alter the formatting of .golden
files, although we will be mindful of such changes.
- Major versions of autogold (e.g.
v1
, v2
) will be used for any major changes in output that would be difficult to review (we expect this will be rare in practice.)
Alternatives comparison
The following are alternatives to autogold, making note of the differences we found that let us to create autogold: