snap

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2024 License: MIT Imports: 12 Imported by: 0

README

Snap

Go Reference

Minimalistic snapshot testing for Go.

Similar to the concept of golden files, but instead of a separate file that contains the snapshot, the snapshot is directly in the source code tests.

Video

Highlights:

  • Simple, minimal API.
  • Provides automatic updating of the shapshot in code. Can trigger via environment variable SNAP_UPDATE=1 to update all snapshots at once, or can update one test at a time using the Update method.
  • Leverages the powerful go-cmp package for displaying rich diffs when the snapshot differs from what is expected.
  • Ability to ignore part of the input text by using a special <snap:ignore> marker.

Limitations:

  • When updating a snapshot that uses the <snap:ignore> marker, the marker is overwritten. This can be worked around by undoing that specific line back to the ignore marker(I do this easily with Git hunks), but it is indeed a little annoying to deal with.

Inspired by:

Usage
func TestExample(t *testing.T) {
    checkAddition := func(x int, y int, want *snap.Snapshot) {
        got := x + y
        want.Diff(strconv.Itoa(got))
    }

    checkAddition(2, 2, snap.Snap(t, "8")) // should be 4
}

Running that test will fail, and prints the diff between the actual result (4) from the checkAddtion function, and what is specified in the snapshot:

=== RUN   TestExample
    snap_test.go:149: snap: Snapshot differs: (-want +got):
          string(
        -       "8",
        +       "4",
          )
    snap_test.go:149: snap: Rerun with SNAP_UPDATE=1 environmental variable to update the snapshot.
--- FAIL: TestExample (0.00s)

To update that snapshot automatically without manually editing the code, rerun the test with SNAP_UPDATE=1 and it will change snap.Snap("8") to snap.Snap("4") for you.

This is a small example, this testing strategy really speeds things up when you have large outputs that need changing, such as large JSON blobs or any substantial amount of text.

Ignoring data

Sometimes you have data in tests that change on each run. Such as timestamps, or random value. These values can be ignored using the special marker <snap:ignore>.

This example shows how to ignore a JSON field. The timestamp field in the person struct will be ignored when diffing the expected and got data.

func TestSnapJSONWithIgnore(t *testing.T) {
    checkJSON := func(want *snap.Snapshot) {
        type person struct {
            Name string    `json:"name"`
            Age  uint      `json:"age"`
            Time time.Time `json:"timestamp"`
        }

        p := person{
            Name: "Doug",
            Age:  20,
            Time: time.Now(),
        }

        want.DiffJSON(&p, "  ")
    }

    checkJSON(
        snap.Snap(t, `{
  "name": "Doug",
  "age": 20,
  "timestamp": "<snap:ignore>"
}`))
}
Examples

The ./examples directory showcases some more elaborate use cases for this package, such as testing a CLI application.

The tests for this package might also serve as a good reference.

Documentation

Overview

Package snap provides a simple implementation of Snapshot testing in Go.

The Snap function provides the ability for diffing with other strings, and can update it's own source code to match the expected value.

Usage:

func TestAddition(t *testing.T) {
  checkAddition := func(x int, y int, want *snap.Snapshot) {
      got := x + y
      want.Diff(strconv.Itoa(got))
  }

  checkAddition(2, 2, snap.Snap(t, "8")) // should be 4
}

Running that test will fail, printing the diff between the actual result (`4`) and what is specified in the source code:

    snap_test.go:34: snap: Snapshot differs: (-want +got):
          string(
        -       "8",
        +       "4",
          )
    snap_test.go:34: snap: Rerun with SNAP_UPDATE=1 environmental variable to update the snapshot.
--- FAIL: TestAddition (0.00s)

Re-running the test with SNAP_UPDATE=1 environmental variable will update the source code in-place to say "4". Alternatively, you can use Snapshot.Update to auto-update just a single test.

Snapshots can use the `<snap:ignore>` marker to ignore part of input. This is helpful when dealing with values that change between test runs, like timestamps:

func TestSnapTime(t *testing.T) {
	timestampStr := fmt.Sprintf("Unix time is %d ms", time.Now().UnixMilli())

	snap.Snap(t, "Unix time is <snap:ignore> ms").Diff(timestampStr)
}

Main idea and influence came from these articles:

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Snapshot

type Snapshot struct {
	// contains filtered or unexported fields
}

func Snap

func Snap(t *testing.T, text string) *Snapshot

Creates a new Snapshot.

Set SNAP_UPDATE=1 environment variable or call the Snapshot.Update method to automagically update the test value.

func (*Snapshot) Diff

func (s *Snapshot) Diff(got string)

Diff compares the snapshot with a given string. It calls testing.T.Error when the snapshot is not equal to the value or when an error is encountered elsewhere.

func (*Snapshot) DiffJSON

func (s *Snapshot) DiffJSON(value any, indent string)

DiffJSON compares the snapshot with the json serialization of a value. It calls testing.T.Error when the snapshot is not equal to the value or when an error is encountered elsewhere.

func (*Snapshot) Update

func (s *Snapshot) Update() *Snapshot

Update allows updating just this particular snapshot.

Directories

Path Synopsis
examples
cli

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL