Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby code coverage without all the requires and method defintions?

Tags:

ruby

simplecov

When using a super simple simplecov setup like

require 'simplecov'
SimpleCov.start

I get loads of "coverage" for files and code that were not really "executed" (in any sense that I would care about when looking at code coverage for a specific test) at all with the individual test I was running.

For example all the require, module, class, def, attr_accessor etc. are marked in green for all files that were loaded on the coverage report generated. I do not care about those, and would be happy if those files would report 0% coverage if no "actual code" was executed in them.

end, rescue and comments for example are considered not relevant and not marked red or green in any files. I would like similar behavior for the methods listed above.

Is there a way to get a code coverage that really only includes (and measures) the actual code lines being executed that I care about?


Update after first answer: Marking all other code as "not relevant" via e.g. # :nocov: is unfortunately not an option as this would affect thousands of files for each individual test run.

like image 226
janpio Avatar asked Mar 18 '26 15:03

janpio


1 Answers

SimpleCov is simply showing you what Ruby's Coverage library collects and as the comments on your question have said, those things are executed, but I too find this frustrating - I don't want a class that's loaded, but not used, to be at 40% coverage.

My solution is to remove coverage that only occurs as part of the loading process. We're using Rails, so we start by loading every file in the application (this is easy in rails, there's a eager_load config); take a snapshot of coverage at that time; run the test suite; then finally deduct the snapshot from the final result before simplecov outputs. Any line covered exactly once in the load snapshot and exactly once in the final result is removed.

Below is a custom SimpleCov formatter I cobbled together a while back that does this job. It's a bit of a hack since it messes with the internal result object of the gem, so be aware that it might not be stable for new versions, but it's working for us with the current simplecov (0.16.1). Also note that since it uses Coverage.peek_result this requires Ruby 2.3 or later.

Use it by setting SimpleCovWithoutLoadingFormatter as your formatter for simplecov and in your test suite setup call SimpleCovWithoutLoadingFormatter.take_load_snapshot immediately after loading every file your application.

require 'simplecov'

class SimpleCovWithoutLoadingFormatter
  def self.take_load_snapshot
    @coverage_load_lines_mask = Coverage.peek_result
  end

  def self.coverage_load_lines_mask
    @coverage_load_lines_mask
  end

  def format(result)
    if self.class.coverage_load_lines_mask&.any?
      result_merge_count = result.command_name.split(',').count

      result.files.each do |source_file|
        _file, load_mask = self.class.coverage_load_lines_mask.detect { |file, _load_mask| file == source_file.filename }
        next unless load_mask

        source_file.coverage.each_with_index do |count, i|
          source_file.coverage[i] = nil if count&.positive? && count&.==(load_mask[i] * result_merge_count)
        end
      end
    end

    SimpleCov::Formatter::HTMLFormatter.new.format(result)
  end
end
like image 160
DMA57361 Avatar answered Mar 20 '26 15:03

DMA57361



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!