I wanted to try building a small, RESTful API for a mobile app. And, like any respectable piece of software, I wanted close to 100% test coverage.
The Premise: Signature Collection for Petitions
I built an API to collect signatures for online petitions. Each signature is composed of a name, age, and short message. The server responds to the following requests:
HTTP Verb
Path
Use
GET
/signatures
List all signatures
POST
/signatures
Create a signature
The Dependencies
Martini: A Go web framework, like Sinatra. Used for routing.
mgo: Pronounced "mango". A Go driver for MongoDB, used to persist the signatures.
gory: Used to easily create signatures for unit testing.
If you're following along at home, you'll need to go get these libraries:
go get github.com/go-martini/martini
go get github.com/martini-contrib/binding
go get github.com/martini-contrib/render
go get labix.org/v2/mgo
go get github.com/onsi/ginkgo
go get github.com/onsi/gomega
go get github.com/modocache/gory
You'll also need MongoDB. On OS X you can install it via Homebrew, with brew install mongodb.
I need to connect to MongoDB to retrieve and insert signatures. The main database will eventually contain tons of signatures, but I want my unit tests to run with a fresh database every time.
Therefore, when establishing a session, I'll allow the caller to specify the name of the database. The main app database will be called "signatures", and the tests will use "signatures_test".
Defining the Routes
The server responds to requests by retrieving or creating signatures.
Taking the Server Out for a Spin
Having built the server, it's time to see if it actually works. I define an executable in main.go that creates a new server object and runs it.
Now it's time to compile and run this bad boy. You'll need mongod running on a standard port, then execute:
src/signatures/ $ go install
src/signatures/ $ signatures
[martini] listening on :3000 (development)
Ginkgo provides a command-line executable to generate unit tests.
src/signatures/signatures/ $ ginkgo bootstrap
Generating ginkgo test suite bootstrap for test in:
signatures_suite_test.go
src/signatures/signatures/ $ ginkgo generate server
Generating ginkgo test for Server in:
server_test.go
Ginkgo uses signatures_suite_test.go to kick off the unit tests, which are contained in server_test.go.
My unit tests will be creating a bunch of Signature objects, both valid and invalid. I don't want to write a bunch of object creation boilerplate in my unit tests, though, so I used an object factory.
Writing the Tests
Now it's time to actually write the unit tests.
Note that when I built this application, I tested throughout its development. I don't recommend you save your tests for the very end. I've done so in this post so as to present the material more clearly.
Testing HTTP in Go is a snap, thanks to the httptest package in the Go standard library. For more information, this blog post by Pivotal Labs is spectacular.
The gist is that we can use an instance of *httptest.ResponseRecorder to access responses from our server.
Running the Tests
Our tests get us pretty great coverage:
src/signatures/ $ ginkgo -r --randomizeAllSpecs -cover
Running Suite: Signatures Suite
===============================
Random Seed: 1399880786 - Will randomize all specs
Will run 8 of 8 specs
...
Ran 8 of 8 Specs in 5.055 seconds
SUCCESS! -- 8 Passed | 0 Failed | 0 Pending | 0 Skipped PASS
coverage: 93.5% of statements
Ginkgo ran in 8.278165839s
Test Suite Passed
Note that you need MongoDB running in order to execute the tests.
Where to Go from Here
You can check out the source code for this project on GitHub. Try adding some features and sending a pull request:
Prevent users with the same email from submitting multiple signatures, even if they use "dudebro+foo@example.com"
Add a route to show a single signature, using its email address as a key