Continuous Integration in Go: Ginkgo & Coveralls
I've recently started programming in Go. But you can't really call it programming without:
- a comprehensive set of tests
- a CI server to make sure they're all passing
I took some time to see what was available in Go. I came up with the following:
- Unit tests: Ginkgo & Gomega
- Continuous Integration: drone.io (or Travis CI)
- Code coverage: Upload metrics to coveralls.io using Gover and Goveralls
Unit Tests with Ginkgo
If you've used RSpec (Ruby), you'll love Ginkgo and its matcher library Gomega:
var _ = Describe("Set", func() {
var set *Set
BeforeEach(func() { set = NewSet() })
Describe("adding and removing elements", func() {
It("adds elements", func() {
set.Add("Rails")
set.Add("Django")
Expect(set.Cardinality()).To(Equal(2))
Expect(set.Contains("Rails")).To(BeTrue())
Expect(set.Contains("Django")).To(BeTrue())
})
It("removes elements", func() {
set.Add("iOS")
set.Add("Android")
set.Remove("Android")
Expect(set.Cardinality()).To(Equal(1))
Expect(set.Contains("iOS")).To(BeTrue())
Expect(set.Contains("Android")).To(BeFalse())
})
})
})
To use it, just go get
it using the instructions from the README:
$ go get github.com/onsi/ginkgo/ginkgo
$ go get github.com/onsi/gomega
Continuous Integration
Both drone.io and Travis CI provide CI services for Go. I normally love Travis CI, but found them to be pretty slow when booting a new Go job, so I decided to give drone.io a try. I wasn't disappointed!
Unlike Travis CI and its .travis.yml
file, drone.io has you edit your build script online. That means you don't check it into your project. Users can still see the script by accessing your project's drone.io URL.
I can think of pros and cons to this approach, but who cares? drone.io starts jobs crazy fast.
Both Travis CI and drone.io are free for public projects. It's also very easy to setup:
- drone.io: https://drone.io/
- Travis CI: https://travis-ci.org/
Publishing Code Coverage Metrics
Go was designed with tools in mind, and code coverage is no exception. It's stupid easy to generate code coverage reports:
$ go test -cover
Uploading metrics to coveralls.io is simple as well, thanks to a Go package called goveralls:
$ go get github.com/mattn/goveralls
$ goveralls -service drone.io \
-coverprofile=example.coverprofile \
-repotoken $COVERALLS_TOKEN
I encountered one minor snafu, however. You see, you can run all the tests in your current directory, recursively, using:
$ go test ./... -cover
But doing so generates coverage reports in each directory, while goveralls only supports uploading a single report.
So I created a tool called gover. gover collects all of your coverage reports into a single report (called gover.coverprofile
by default):
$ go get github.com/modocache/gover
...
$ go test ./... -cover
...
$ gover
$ goveralls -service drone.io \
-coverprofile=gover.coverprofile \
-repotoken $COVERALLS_TOKEN
All Together
Putting it all together, I got a CI script that looks something like this:
#!/bin/bash
# go get dependencies
go get code.google.com/p/go.tools/cmd/cover
go get github.com/modocache/gover
go get github.com/mattn/goveralls
go get github.com/onsi/ginkgo/ginkgo
go get github.com/onsi/gomega
go get -v ./...
# test all tests recursively (like `go test ./... -cover`)
ginkgo -r --randomizeAllSpecs -cover
# submit coverage report
gover
goveralls -service drone.io \
-coverprofile=gover.coverprofile \
-repotoken $COVERALLS_TOKEN
For an example of a project using this setup, just check out gover itself! For more on Go and testing, check out RESTful Go: An API Server with 90%+ Test Coverage in 260 Lines of Code.
Tweet