---
title: Why Do Rubyists Test So Completely?
teaser:
tags: web,ruby,testing,good code
author: Mike Burns
published_on: 2009-08-14
---

The Ruby community, according to some data I am making up, has the strongest
test-driven development attitude. Not all of us
[TATFT](http://smartic.us/tag/tatft/); not all of us test most of the time; and
not all of us test ever&mdash;but those who do test make up a larger proportion
than they do in, say, the Java world.

But why? What is it about Ruby that drives us to attain 100% [code
coverage](https://thoughtbot.com/blog/post/159806234/simple-test-metrics-in-your-rails-app-and-what-they)?

## Cultural Pressure

We test. [Kent Beck](http://www.threeriversinstitute.org/Kent%20Beck.htm) tests.
Rails comes set up for you to write tests as part of your application. Are you
such a skilled programmer, such a badass rebel, such a unique person, and such a
loner that you wouldn't dare test your Ruby code?

No, because your app would break and you know it. More importantly, everyone in
the community knows it. If you publish it to [Rubyforge](http://rubyforge.org/)
and there are no tests, don't expect us to use it. So you write tests, because
we want you to.

(Thank you for doing that for us.)

## It's a Mindset

Test-driven development is cheating. [You think
upfront](https://thoughtbot.com/blog/post/159806273/non-test-code-is-trivial)
about the problem, the solutions, the problems with those solutions, and you
document all this in code. It fails, with a pretty error message, so you make it
pass.

But you already know this one.

## nil

Any method, at any time, might produce `nil`. You never know when it might
happen. Even instance variables might produce `nil`. Your code will keep going
until this becomes an issue&hellip;and it _will_ become an issue.

The reason `nil` appears so often, even when unexpected, is in part because of
the implicit return at the end of methods, and in part because `if` in Ruby is
different from `if` in C (it's an expression that produces a value instead of a
statement that just runs). This is different from what many people expect and
this difference often goes ignored.

We've worked around this in places where we expect `nil`. Either we re-write the
algorithm to `#compact` the `nil`s out early, or we use `#validate_presence_of`
and stop expecting `nil`, or we use [the `#try`
hack](http://ryandaigle.com/articles/2008/11/20/what-s-new-in-edge-rails-object-try),
or some other specific solution. But it lingers in the back of our mind that any
method we're calling could produce an absolutely useless value.

## No static analysis

We have to write complete tests that verify the runtime code because there is no
tool to automate this. In a world where even C can tell you when you are passing
an integer where it expected a string&mdash;before even running your
program&mdash;Ruby cannot do anything of the sort. Your program works until it
stops working, and then you dig through [Hoptoad](http://hoptoadapp.com/) for a
minute, write a test for 30 minutes, fix the code (five minutes), and re-deploy.
Live, while the client is waiting.

So we write the tests first so the client stays happy. Instead of just hacking
away at code until it compiles, we write tests then hack away at code until they
pass.

Work has been done to try to statically analyze Ruby. Our very own [Jason
Morrison](mailto:jmorrison@thoughtbot.com) did [some work in 2006 for the Google
Summer of Code to build a type inference engine](http://soc.jayunit.net/), then
tried to continue [the project before abandoning the
idea](http://rti.jayunit.net/); according to him, the main problem is `eval`.
Another problem he's mentioned is the way classes are implemented, with the
singleton classes and mixins and whatnot. Ping him for more information.

## <s>Refactoring</s> Mutation

We write tests so we can refactor without care. What if we change the methods
called, or the order of the callbacks; what will break?

This matters because code can depend on ordering. Variables can be mutated: set,
unset, and changed from anywhere. We might print to the logger in one callback
then follow-up that printing in another. We might depend on an instance variable
not being `nil` in a method because of undocumented invariants. If we re-write a
seemingly innocent method in a way that changes the order in which things are
mutated, _anything_ could go wrong.

## So What

So we test because Ruby provides no better alternative, and because testing is
awesome. What if we tested only because we enjoyed it, not because we got
anything technical out of it? What if our unit tests never failed except for
when we first wrote them? What if regressions were caught by the language
implementation instead of by custom code?

**What changes would you make to Ruby to achieve the goal of never unit testing
again**?
