Ginkgo and Gomega: BDD-Style testing in Go
Why you should use Go
Go is an open source platform as a service and is much faster than languages like Ruby and provides easy methods for moving your Command Line Interface from Ruby to Go. Ruby, however, has a much larger developer ecosystem with Rails giving so much away for free for Ruby. In Go, the largest problem is how to test in the new ecosystem.
Software is often written to satisfy a specification. This is a static idea isolated from the code and makes it hard to verify the specifics and test the code for errors. To do so you need to take code and write unit tests and then wrap them with integration tests. Writing dynamic tests integrated with the code allows you to have repeatable verifiability and guarantees that your code will work as you refactor, add new features, and as you change components.
At Pivotal Labs, test driven development comprised of tests, red, code, refactor, repeat takes the front stage. This is because through the discipline of first running tests, then code covers all the bases and guarantees that there is a test for everything. This pushes forward that tests are communication and that pairing programming and better documentation with consistent testing creates better code than just comments. This pushes the idea that better code is better because it has to be testable compared to untestable code that collapses into a "big pile of spaghetti" when it fails.
Testing in Go
The first myth is that testing is unnecessary in a compiled statistically typed language. This is false. A compiled language can make guarantees about interfaces and types but not about the behavior of an object let alone objects inside. Testing in Go is considered a first-class citizen, in fact it's as easy as import, write and run tests. This is done through xUnit style tests with no matcher/assertion library. The reason is because it is easy to write unit tests that lack features such as assertion functions and that testing frameworks tend to develop into mini-languages of their own.
Using the base testing in Go is hard using the included methods because the documentation is unclear, there's lots of repeated setup and lots of repeated custom error handling. Making it into one large test doesn't help, as does making it a table driven test because neither is clearer. This leads to the tests having 1.5 to three times as much code as the actual code.
By using Ginkgo and Gomega you get access to BDD-style testing for Go. Ginkgo is the testing framework with Gomega acting as the matcher library. These are both available through github in Go and give rich semantics for describing your code's behavior. The shared test setup and teardown, short descriptive isolated tests and nested contexts make testing code branches natural while the tests themselves act as specification and documentation. The BDD-style promotes effective pairing and test coverage and while young, Ginkgo acts very mature for a testing platorm.
Gomega allows for and prefers one-line assertions and provides consistent descriptive output for free. With a rich library of matchers and the ease of writing custom matchers Gomega allows you to expressively describe the behavior of your domain.
Gomega + Ginkgo = Better testing in Go
Gomega and Ginkgo provide the BDD-style testing designed for Go and are built out of a deep respect for Go. They integrate well with Go's test runner to the point of not having to throw everything out the window and start building tests again, you only have to start testing in Gomega. This provides a comprehensive support for asynchronous tests that Gomega extensively supports.
For more information, go to github.com/onsi.ginkgo and github.com/onsi/gomega
Docker: an inside view
What is Docker?
Docker is here to solve the matrix from hell. Developers have tons of stuff to deploy and tons of places to deploy it nowadays but there is no single solution to do so. The solution is Docker, an intermodal shipping container. This includes high and low level approaches such as linux containers, miniature Virtual Machine containers and more and has been described as chroot on steroids. Docker is a runtime for linux containers and provides a standard format and place to share them so developers and fetch an image from the registry with a docker pull and enter the image with docker, run and change.
Go is built on static compilation and using the go build command will embed everything you need save for dynamic libraries through cgo and libc. You can even have a real static binary if you hack the build process! Go is easier to install, easier to test, easier to adopt and is a good candidate for bootstrap. This is because it is neutral. While having a few things in common with C it is not C, nor python, ruby or java. It has what developers need, good asynchronous primitives, low-level interfaces, extensive standard library and data types and strong duck typing. It provides a full development environment by addressing multiple issues of the development workflow.
There are drawbacks to using Go, however. It doesn't solve any problem, but it is easier than erlang and more real than rust. Maps aren't thread-safe, but that is a deliberate decision. They are fast and you can protect access with sync.Mutex or using channels of channels. Go get can't pin a particular revision, a problem Docker has had to deal with by vendoring all dependencies so developers must deal with private repositories manually. Go test can't have destructors or cleanups. In tests, you have use tests like z_frinal_test.go that don't work too well when running individual tests. Go build is painful to build multiple binaries when they share some common code and yet each program has to be in in its own package. You can bypass this by making a package 'main' but then you have to put shared or common stuff aside or use import tricks. Flagging is just right out and there's no IDE. These are all made easier if you use VIM or EMACS.
For more information on Docker, check Docker.io. Other helpful resources for using Go with Docker, check out:
embedded doc: godoc -http=:6060 & chrome http://localhost:6060