autogold

repository·main·Indexed 43 days ago

https://github.com/hexops/autogold

A tool for Go developers that automates the updating of test snapshots. It supports both external golden files via `autogold.ExpectFile` and inline Go values via `autogold.Expect`, allowing developers to update expected test results by running `go test -update`. Features include support for table-driven subtests, custom formatting options like `ExportedOnly()`, and Bazel compatibility.

Tokens
3.2K
Snippets
19
Records
21
Agent score
37%

What's inside autogold

  1. Support for table-driven subtests

    main

    Autogold supports table-driven Go subtests. By calling .Equal(t, got) inside the t.Run loop, autogold uses callstack information to find the corresponding autogold.Expect(nil) call in your test table and updates the specific value for that subtest case.

    func TestTime(t *testing.T) {
    	testCases := []struct {
    		gmt    string
    		type   string
    		expect autogold.Value // autogold: the value we expect
    	}{
    		{"12:31", "Europe/Zuri", autogold.Expect(nil)},
    		{"12:31", "America/New_York", autogold.Expect(nil)},
    		{"08:08", "Australia/Sydney", autogold.Expect(nil)},
    	}
    	for _, tc := range testCases {
    		t.Run(tc.loc, func(t *testing.T) {
    			// ... setup logic ...
    			got := ... 
    			tc.expect.Equal(t, got) // autogold: updates the nil in the table
    		})
    	}
    }
  2. Use automatic golden files

    main

    Golden files are used for snapshot testing, which is ideal for large multi-line strings or complex Go structures. When you use autogold.ExpectFile, running go test -update will automatically create or update a .golden file in the testdata/ directory corresponding to the test name.

    To remove unused golden files, use the -clean flag: go test -update -clean.

    import "github.com/hexops/autogold/v2"
    ...
    autogold.ExpectFile(t, got)
  3. Enable Bazel compatibility via environment variable

    main

    Because Bazel sets PATH=".", standard Go tooling (like golang.org/x/tools/go/packages) often fails due to security concerns. To use autogold in a Bazel environment, you must enable the package name inference hack by setting the following environment variable:

    ENABLE_BAZEL_PACKAGES_LOAD_HACK=true

    When enabled, autogold will attempt to guess package names and paths using stack trace information instead of relying on packages.Load. Note that this method may not work for packages where the import path does not match the defined package statement.

    export ENABLE_BAZEL_PACKAGES_LOAD_HACK=true
  4. Use automatic inline test updating

    main

    For inline snapshots, call autogold.Expect(want).Equal(t, got), passing nil as the initial want value. When you run go test -update, autogold will rewrite the source code of your test, replacing nil with the actual Go value produced by the test. This works for complex structs, slices, and strings.

    func TestFoo(t *testing.T) {
    	...
    	autogold.Expect(nil).Equal(t, got)
    }
  5. Use the Raw type for unformatted golden files

    main

    By default, ExpectFile formats the got value as a Go literal. If you want to use the raw contents of a type (e.g., for byte slices or specific string formats) without Go-style quoting or formatting, ensure the value passed to ExpectFile implements the Raw type.

    When Raw is used, if the resulting string is empty and the -clean flag is active, ExpectFile will automatically remove the corresponding .golden file.

  6. Update expected values with the -update flag

    main

    If a test fails due to a mismatch, you can automatically update the expected value in your source code by running your tests with the -update flag.

    autogold identifies the specific autogold.Expect(...) call site using the runtime callstack and replaces the want argument with a string representation of the got value. The updated file is then processed with goimports to ensure correct formatting and imports.

    go test ./... -update
  7. Configure custom formatting and options

    main

    You can customize how values are represented in golden files or inline tests:

    • String formatting: Pass a string to autogold.Expect to have it treated as a Go string.
    • Raw values: Use autogold.Raw("value") to use a custom format (like JSON) as-is for .golden files. Note: autogold.Raw is not supported for inline tests.
    • Exclude unexported fields: Use autogold.ExportedOnly() to only include exported fields in the output.
    // Exclude unexported fields
    autogold.ExpectFile(t, got, autogold.ExportedOnly())
    
    // Use custom raw formatting (for files only)
    autogold.Expect(autogold.Raw(`{"key": "val"}`))
  8. Run tests with the -update flag

    main

    To trigger the automatic updating of golden files or inline test values, append the -update flag to the end of your go test command.

    Note: It is important to put -update at the end to ensure that stdout is not treated as a terminal, which prevents colorization issues in some environments.

    go test -count=1 -run TestSomething . -update
  9. Configure autogold behavior with Options

    main

    The autogold.Equal function (and related API) accepts Option types to customize how golden files are generated and stored. You can use functional options to control whether only exported fields are included, specify a custom filename, or change the directory where golden files are saved.

    // Example usage of autogold options
    // Note: This assumes the existence of an Equal function that accepts these options.
    err := autogold.Equal(t, actual, expected, 
        autogold.ExportedOnly(),
        autogold.Name("my_custom_test"),
        autogold.Dir("custom_testdata"),
    )
  10. Register a custom Bazel package resolver

    main

    If you are using Bazel and encounter packages where the import path does not match the defined package name, you can provide a global custom resolver. This resolver maps a package path to its correct package name.

    Important: You should call RegisterBazelPackagePathToNameResolver as early as possible, preferably within an init() function. Because this is a global singleton, it can only be registered once.

    package mypackage
    
    import "github.com/hexops/autogold"
    
    func init() {
    	// Register a custom resolver to handle problematic package mappings
    	autogold.RegisterBazelPackagePathToNameResolver(func(path string) string {
    		if path == "github.com/example/problematic/path" {
    			return "correct_name"
    		}
    		return ""
    	})
    }
  11. Configure ExpectFile with Options

    main

    The ExpectFile function accepts optional Option arguments to customize how golden files are located and named.

    Supported Customizations:

    • Custom Directory: Specify a different directory for storing golden files (defaults to testdata).
    • Custom Name: Specify a custom name for the golden file (defaults to the current test name).
    • Raw/Newline behavior: Internal options like allowRaw and trailingNewline are applied automatically to ensure consistent diffing.