Writing Expressive tests in Go with Ginkgo and Gomega
Testing is a subject extremely close to my heart. I talk (write) about it all the time and one of the reasons I fell in love with Go was the simplicity of the testing standard library alongside it’s ease of usage.
But simplicity is actually complicated. With simple and tiny test suites (e.g the universally accepted calculator example), the standard testing library is spot on. But with larger and complex tests, the testsuite starts to feel clunky, complex and for the most part, difficult to read and follow through - which for me is a miss.
This testsuites starts to feel as it was the application’s code itself. Tons of
if/elses (too much details in the tests) and the likes. Just to be clear, I take my test code as important as the application code itself. But then again, I am a big fan of readability when it comes to testing and I have noticed that is quite hard to get if I make use of the testing package provided in the standard library.
While searching for an alternative, I came across Ginkgo and Gomega. Ginkgo is a BDD testing framework for Go while Gomega is a test matcher/assertion library.
Why Ginkgo ?
- Enforces tests to access only the exported values/symbols of a package. This was the subject of a previous blog post. This can be overridden by changing the package name though.
Since Ginkgo is a BDD framework, we would be dropping a lot of stuffs we learnt from xUnit and get used to stuffs like
Expect: To run an assertion
It: To describe a test suite
Context: Well, to add more context (description) to a test suite
So, what does this looks like in real life ?
Let’s write some code to determine the type of a triangle (equilateral, isosceles, or scalene).
This is an exercism from exercism. You should checkout that website, tons of cool stuff in there
I created a package in my
We are done with our package, the next obvious thing is to write the tests. We would be needng to install
gomega. They are go gettable as
The way ginkgo works is a little bit different from how the standard library works. So we would need to (automatically) create a
bootstrap file for our tests, this is for compatibilty with the standard library test runner i.e
go test. To generate the bootstrap file, we would run
ginkgo bootstrap. After which we would run
ginkgo generate file_name.goin other to generate a test file.
Here is what the generated test file looks like :
You can get rid of the dot(.) imports.
Let’s fill that dummy test suite up
You should run
go test, although the latter would work too - if you ran the
ginkgo bootstrapcommand earlier.
This should be readable and denotes what the test does. On failure, you get a nice stack of the description anyways. How comparable is this to
The one with the standard library is just complex and non-readable as the BDD version (with Ginkgo).
Let’s complete the test for
There are also some more interesting concepts Ginkgo (BDD ?) has which I feel makes it far superior than the standard testing library. There is the
AfterEach hooks for you to do clean up and tear down as in xUnit style.
Although it is possible to implement setup and teardown with the standard testing library, it is just a ltttle bit of more code
Another thing I love about Ginkgo is the way table driven tests are written… Freaking neat. Here is an example from filer
PS : If you need to take a look at packages/projects that makes use of this, you can checkout Kubernetes and filer