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:

[ruby]return unless Features.wiki_ed?[/ruby]

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

[ruby]
class Revision < ActiveRecord::Base
scope :after_date, ->(date) { where(‘date > ?’, date) }
end
[/ruby]

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:
[ruby]
class Article < ActiveRecord::Base
def update(data={}, save=true)
self.attributes = data
self.save if save
end
end
[/ruby]

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.

255 thoughts on “First impressions of Ruby branch coverage with DeepCover”

  1. DeepCover co-author here. Thanks for the great examples. The unused scope is probably fairly typical. You mention unused default arguments (which DeepCover can detect), but in the update case, I imagine that the default argument was always used (which we should detect) and that it’s actually DeepCover’s branch coverage that alerted you to the face that `if save` was always true, right?

    1. I think it’s that the default argument was always used, but it was detecting that nothing *except* the default argument was used. I’m not completely sure, though.

      The `def` line is the one that was marked as uncovered. (I did this via simplecov, so I didn’t get the visualization of the uncovered parts within the line.)

Comments are closed.