特定のファイルに対して一定のテストカバレッジを保証する

ある特定のファイルのテストカバレッジが、ある特定のテストファイル(群)を実行したときに一定のカバレッジ率であることを保証したいと思うことはありますか?私はあります。

そこで、 次のような spec/coverage_helper.rb を用意して、 spec/rails_helper.rb などから require すると、 COVERAGE_ASSERTION=app/models/ability.rb rspec spec/models/ability_spec.rb:99 のようなコマンドをCIで実行したときに一定のテストカバレッジ以下のときにCIがコケるようにしました。

# frozen_string_literal: true

class CoverageAssertion
  class CoverageAssertionFailure < StandardError
  end

  attr_reader :file_map
  attr_reader :highline

  def initialize
    require "highline"

    coverage_assertion = ENV['COVERAGE_ASSERTION']
    @file_map = Hash[coverage_assertion.split(',').map { |pair| pair.split(':') }]
    @file_map.transform_keys! { |key| Pathname.new(key) }
    @file_map.transform_values! { |value| value.to_f }

    @highline = HighLine.new
  end

  def format(result)
    failure_message = +""
    result.groups.each do |_name, files|
      files.each do |f|
        filename = Pathname.new(f.filename).relative_path_from(Rails.root)
        threshold = file_map[filename]
        if threshold && f.covered_percent < threshold
          failure_message << highline.color("#{filename}: expected at least #{threshold}% but got #{f.covered_percent.round(2)}%\n", :red)
        end
      end
    end

    if failure_message.present?
      raise CoverageAssertionFailure, "Coverage assertion failed!\n#{failure_message}"
    end
  end
end

if ENV['CI'] || ENV['COVERAGE'] || ENV['COVERAGE_ASSERTION']
  require 'simplecov'
  require 'simplecov-lcov'

  # COVERAGE_ASSERTION="$file1:$least_coverage1,$file2:$least_coverage2,..."
  # See also .circleci/config.yml
  if ENV['COVERAGE_ASSERTION']
    SimpleCov.formatter = CoverageAssertion
  else
    SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
      [
        SimpleCov::Formatter::HTMLFormatter,
        SimpleCov::Formatter::LcovFormatter,
      ],
    )
  end

  SimpleCov.start 'rails' do
    # add_filter [...]
  end
end

Rails + rspec + simplecov という条件で動くはず。