When we started developing the Tonsser API we decided to give test driven development (TDD) a shot and see how it went. This decision was mostly lead by the fact that the Ruby community is very pro testing and speaks very highly of its benefits.
It has now been 4 years and we’re still all in on TDD. I strongly believe the reason we have such a solid API is because testing is a core part of our workflow.
I really don’t know how I would work without tests. When you’re building a web app you can test it manually by clicking around in the browser. When you’re building an API things aren’t so simple. You would have to use curl or Postman, which would get tedious quickly. And I can’t imagine manually testing a complex flow containing a mix of
With automated tests we are able to setup exactly the state we need, call one or more endpoints, and make assertions about the JSON we get back. Here is what a typical integration test looks like:
describe "GET /me" do it "returns a user's name" do user = create :user get_as_user user, "/me" expect(json.response.name).to eq user.name end end
At the time of writing we have over 4000 tests and more than 95% test coverage. That means shipping stuff that breaks something else happens very rarely. Our productivity has also not declined overtime as the app has grown, and our code isn’t a “big ball of mud”. I still enjoy building new features as much as I did in the first month.
Another important benefit of testing is how it allows us to refactor relentlessly. You rarely get stuff right the first time and things always change when you’re in a fast moving startup. Our strong focus on testing supports that well by allowing us to safely refactor large fundamental systems such as deep linking and ditching ActiveModelSerializers.
The hardest part about testing is always selling it to managers. It is easy to think that writing tests will slow you down because you have to spend time writing both test and implementation code. But this view is very short-sighted. Testing actually increases productivity because you’ll be spending less timing fixing things you broke by accident. It of course helps to have done TDD from day one and to use a framework like Ruby on Rails which has great built in support for testing.
One of the downsides of having lots of tests is that you sometimes have to spend time updating them. If 100 tests depend on some object, and that object changes, you have to update your tests. That is sometimes a bit tedious but the trade-off is well worth it. I’m also sure the time saved by having tests is greater than the time spent updating them.
We currently have lots of open positions in tech so if you like our approach to testing I encourage you to check them out at tonsser.com/jobs.