I am 💯 and you can too.

100% test coverage! Catch all the bugs!

I’ve been working on a Ruby on Rails app for more than three years, and Ruby coverage for its rspec test suite has been at 100% for most of the last year. 😀

People with more experience may try to tell you this is a bad idea. Test what you need to test. 90% is a good rule of thumb. If you’re doing TDD right, you’ll be testing based on needs, and coverage will take care of itself.

No! Do it!


  • You’ll learn a lot about Rails, your gem dependencies, and your test tools.
  • It’ll help you write better tests and more testable code.
  • You will find bugs you didn’t know about!
  • It’s fun! Getting those tricky bits tested is a good puzzle.
  • Once you get there, it’s easy to maintain.

Okay, but how?


You may have heard people say that code coverage is a lie. It’s true. For example, there are some tricksy ways to add specs for rake tasks to your test suite, but because rake tasks start from a different environment, they don’t integrate cleanly with simplecov. That’s why we exclude rake tasks from the coverage metrics in my app, even though we do test them.

Sadly, even once you reach 💯, it may be tough to keep it in the long run. Ruby 2.5 introduced a big change in the code coverage API. With that change, it has become possible for code coverage tools to report Branch Coverage rather than just line coverage, so the tricks with conditional modifiers and ternary operator may still not get you to 100% in the future. (The deep-cover gem also does this, without requiring Ruby 2.5.) But don’t fret; you’ll probably be able to do something like pin your coverage gem to the last version that just uses line coverage. A small price to pay for the peace of mind of knowing your app is 100% bug free. Or maybe it’s just a number to brag about. Either way, worth it!


Obviously this is not the case. But I still recommend trying to get to 100% coverage, for the reasons listed above.

First impressions of Ruby branch coverage with DeepCover

Branch coverage for Ruby is finally on the horizon! The built-in coverage library is expected to ship in Ruby 2.5 with branch and method coverage options.

And a pure-Ruby gem is in development, too: DeepCover.

I gave DeepCover a try with my main project, the Wiki Education Dashboard, and the coverage of the Ruby portions of the app dropped from 100% to 96.75%. Most of that is just one-line guard clauses like this:

return unless Features.wiki_ed?

But there are a few really useful things that DeepCover revealed. First off, unused scopes on Rails ActiveRecord models:

class Revision < ActiveRecord::Base
  scope :after_date, ->(date) { where('date > ?', date) }

Unlike default line coverage, DeepCover showed that this lambda wasn’t ever actually used. It was dead code that I removed today.

Similarly, DeepCover shows where default arguments in a method definition are never used, like this:

class Article < ActiveRecord::Base
  def update(data={}, save=true)
    self.attributes = data
    self.save if save

This method was overriding the ActiveRecord update method, adding an option to update without saving. But we no longer use that second argument anywhere in the codebase, meaning I could delete the whole method and rely on the standard version of update.