Snapshot testing in Go
Tags: go, testing, unittesting, jest
Published: 2022-01-03 22:08:21

On my journey into learning Go, after some time spent learning the basic concepts I came across the testing. Go has a built-in testing command with `go test` and a testing `package` which combined can be used for unit testing.

It is really useful having native testing capabilities but Go only provides the minimum for writing unit tests. There are no assertions like Mocha or Jest for javascript ( `Equal`, `toBe`), repeated steps (e.g. `beforeEach`, `afterEach`) or mocking/spying and as you would expect by now there is no snapshot testing.

The community has built libraries on top of the standard `testing` package to provide some of the functionality like [testify](https://github.com/stretchr/testify) does.

&nbsp;

## Snapshot testing

Snapshot testing is mostly used when you want to test UIs, as stated in [Jest Docs](https://jestjs.io/docs/snapshot-testing)

> Snapshot tests are a very useful tool whenever you want to make sure your UI does not change unexpectedly.

But snapshot testing can be useful in applications other than UI as well. Some examples could be 

- Database clients, where you want to diff multiple rows of data
- Backend services, where you can diff API responses

and any application that can have a "state" and you would like to create a representation of it and compare it at a later time.

For more information around snapshot testing, there is a wide range of resources you could read for more specific applications and where it fits in unit testing.

&nbsp;

## Go snaps

So I decided to build a library that supports snapshot testing `go-snaps` and practice my Go skills.

It's simple to use

```go
// example_test.go
package example

import (
  "testing"

  "github.com/gkampitakis/go-snaps/snaps"
)

func TestExample(t *testing.T) {
  snaps.MatchSnapshot(t ,"Hello World")
}
```

On the 1st run of your tests this will create a file `__snapshots__/example_test.snap` containing your snapshot

![New snapshot written](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otpktd94n5fls46eojni.png) 

```txt

[TestExample - 1]
Hello World
---

```

On every other run, it will compare this snapshot with the parameters provided.

So if we update the call with

```go
snaps.MatchSnapshot(t,
  "hello world",
  "another value",
  100,
)
```

our test will fail and return a message containing a diff view of the snapshot and params.

![Diff error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mm1uws2ar0vo9uozajll.png)
 
If we are sure this is not a regression in our code and we want to update the snapshots we can call again the `go test` with either flag `-snaps.update=true` or the env variable `UPDATE_SNAPS=true`.

&nbsp;

### Detecting obsolete snapshots

Apart from the standard snapshot functionality that `go-snaps` provides, it also can detect obsolete snapshots (snapshots that are no longer used). In order to enable this functionality you have to use [TestMain](https://pkg.go.dev/testing#hdr-Main) and call the `snaps.Clean()`.

```go
func TestMain(t *testing.M) {
  v := t.Run()

  // After all tests have run `go-snaps` can check for not used snapshots
  snaps.Clean()

  os.Exit(v)
}
```

The reason for using `TestMain`, is because `go-snaps` needs to be sure that all tests have run so it can keep track of which snapshots were not called and mark them as obsolete. 

Again you can remove obsolete tests and files by calling the `-snaps.update=true` or `UPDATE_SNAPS=true`.

![Obsolete snapshots](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qb12vvhngu0nbp6tiwn4.png)
![Remove obsolete snapshots](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tfingcdq31xvceanzmiu.png)
  
&nbsp;

## Conclusion

In the repository, you can find [examples](https://github.com/gkampitakis/go-snaps/tree/master/examples) and more information in [README](https://github.com/gkampitakis/go-snaps#readme).

Hope you find `go-snaps` useful, any feedback is welcome.

## Acknowledgments

[Go Snaps](https://github.com/gkampitakis/go-snaps) used [Jest Snapshoting](https://jestjs.io/docs/snapshot-testing) and [Cupaloy](https://github.com/bradleyjkemp/cupaloy) as inspiration.

- Jest is a full-fledged Javascript testing framework and has robust snapshoting features.
- Cupaloy is a great and simple Go snapshoting solution.

&nbsp;

---

If you liked or found [go-snaps](https://github.com/gkampitakis/go-snaps) useful you can leave a ⭐️.