Snapshot testing in Go
Georgios Kampitakis
Posted on January 3, 2022
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")
}
On the 1st run of your tests this will create a file __snapshots__/example_test.snap
containing your snapshot
[TestExample - 1]
Hello World
---
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,
)
our test will fail and return a message containing a diff view of the snapshot and params.
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)
}
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
.
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 ⭐️.
Posted on January 3, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.