Craig Ambrose

Quick and Easy Ruby Quality Thresholds

Ruby on Rails’ opinionated attitude towards testing has introduced a lot of people to test driven development. Whether it’s because rails development has encouraged good testing practices, or because it has attracted pro-testing developers, rails (and ruby in general) now has a large ecosystem of testing and quality tools.

If you’re a rails developer, you’re probably already writing tests. You’re probably using RSpec or Shoulda (and also Cucumber, but I’m just talking about unit tests here). You’ve probably run your code through rcov, to see how well much code your tests cover, and you’ve probably also looked at other code quality metrics, like the ones generated by metric_fu (or a hosted service like codeyak).

Quality metrics for your code force you to write good code. They are an essential part of test-driven development, because in TDD our design is supposed to be driven by spotting code smells. Unless we think we can get the design (both in the macro and micro) correct first time (and we can’t), then we always have to be on the lookout for these code smells that will drive us to refactor and evolve the design into something better. Since I’m using words like “drive” and “force”, obviously I intend these metrics to be enforced. If you aren’t already doing it, start now.

The following example presumes that you’re testing with rspec, but it only requires slight modifications to make the rcov threshold work with other testing libraries.

First up, ensure that your app has the following gems installed (bundled):

metric_fu, flay, flog, reek, roodi, rspec, rcov

Then, grab my continuous integration rake tasks from here:

http://gist.github.com/364034

Finally, tell your continuous integration server to run “rake ci”. I use cruise_control.rb, but there are plenty to choose from.

You can modify the hash values in the THRESHOLDS constant to set the quality thresholds for your project. Set them so that they just pass at the moment, and then try to improve the code and slowly crank them tighter. For rcov that means raising it (towards 100.0), and for the others, that means lowering them.

Since you’re using metric_fu, you’ll also get graphs and pretty reports of the output. If you’re using cruise_control.rb, look for the “output” link in your build artifacts on the web interface. I’m not executing rcov via metric_fu in my code, because the metric_fu rcov task hides errors in the specs, and we also want the build to fail if a spec fails.