Snapshot testing in Go

Georgios Kampitakis - Jan 3 '22 - - Dev Community

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 does.

 

Snapshot testing

Snapshot testing is mostly used when you want to test UIs, as stated in Jest Docs

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.

 

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

// example_test.go
package example

import (
  "testing"

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

func TestExample(t *testing.T) {
  snaps.MatchSnapshot(t ,"Hello World")
}
Enter fullscreen mode Exit fullscreen mode

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

New snapshot written


[TestExample - 1]
Hello World
---

Enter fullscreen mode Exit fullscreen mode

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

So if we update the call with

snaps.MatchSnapshot(t,
  "hello world",
  "another value",
  100,
)
Enter fullscreen mode Exit fullscreen mode

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

Diff error

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.

 

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 and call the snaps.Clean().

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)
}
Enter fullscreen mode Exit fullscreen mode

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
Remove obsolete snapshots

 

Conclusion

In the repository, you can find examples and more information in README.

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

Acknowledgments

Go Snaps used Jest Snapshoting and 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.

 


If you liked or found go-snaps useful you can leave a ⭐️.

. . . . . . . . . . . . . . .