Categories
Agile Rails Ruby

Are we spending more and more time writing tests?

A while ago I wrote about testing trivialities, and claimed that no matter how simple the piece of code is, it still ought to have a test. I followed it up with some thoughts on using a helper to simplify writing specs for common validations. Even using the helper, the actual test code for a single validation outweighs the production code by a factor of more than three:

Test code:

def valid_attrs
  {
    :username => 'fred',
    :first_name => 'Fred',
    :last_name => 'Bloggs',
    :email => 'fred@bloggs.com',
    :age => 21
  }
end
 
specify_attributes User, valid_attrs,
{
  :mandatory => [:username, :first_name, :last_name],
  :numeric => [:age],
  :min_lengths => {:email => 3},
  :max_lengths => {:username => 12, :first_name => 20, :last_name => 20, :email => 200}
}

Production code:

validates_presence_of :username, :first_name, :last_name
validates_numericality_of :age
validates_length_of :email, :in => 3..200
validates_length_of :username, :maximum => 12
validates_length_of :first_name, :last_name, :maximum => 20
A slight digression: Jay Fields has written an interesting discussion on the pros and cons of testing validations by example (as above) or using mocks. It’s something I’d considered too, but I currently find myself siding with Maxim Kulkin, who points out in the comments that by using mocks you risk breaking tests if you alter the implementation – for example by using a call to validate – even though the behaviour hasn’t changed. I’m not so sure, however, about Maxim’s suggestion that you can conform to one assertion per test by wrapping two assertions in a method.

This seems to be the norm in Rails development – because you can express a lot of behaviour in a small amount of code, you end up spending the vast majority of your time writing tests (or specs). Here are the latest stats for the project I’m currently working on:

rake stats

+----------------------+-------+-------+---------+---------+-----+-------+
| Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Controllers          |   882 |   661 |      17 |      85 |   5 |     5 |
| Helpers              |   239 |   166 |       8 |      14 |   1 |     9 |
| Models               |   336 |   282 |      14 |      25 |   1 |     9 |
| Libraries            |     0 |     0 |       0 |       0 |   0 |     0 |
| Components           |     0 |     0 |       0 |       0 |   0 |     0 |
| Model specs          |  1127 |   916 |       0 |       7 |   0 |   128 |
| View specs           |  1281 |   993 |       0 |       9 |   0 |   108 |
| Controller specs     |  4755 |  3756 |       0 |     132 |   0 |    26 |
| Helper specs         |  1281 |   993 |       0 |       9 |   0 |   108 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total                |  9901 |  7767 |      39 |     281 |   7 |    25 |
+----------------------+-------+-------+---------+---------+-----+-------+
  Code LOC: 1109     Test LOC: 6658     Code to Test Ratio: 1:6.0

Once you add the 1300 or so lines of acceptance/integration code (in Selenium’s RSelenese format), the ratio of production to test code is more like 1:7.

This seems a little high.

One issue with this seems to be that you don’t necessarily see the huge productiity improvements that are sometimes claimed when switching from a Java framework to Rails. Not because the code isn’t more concise and easier to write (I occasionally have to briefly go back to Java, and it can feel quite painful after even a short time writing Ruby), but because you still have to write just as many tests.

Let’s say for the sake of argument that you can implement a feature five times faster in Rails – if the tests take the same amount of time (and assuming you were previously spending half your time on tests), you’re only about 70% more productive, rather than the expected 400%.

So to answer the question in my title, I think the answer is yes. Partly because we’re getting better at really driving development from tests, and partly because we’re using tools that allow us to express behaviour in fewer lines of code. Is this a problem? Probably not, but it’s something to be aware of.

[tags]agile,testing,TDD,BDD,Rails[/tags]

Leave a Reply