Simplecov 测试覆盖率未报告 Rake 任务规范

Simplecov test coverage not reporting on Rake task spec

我一直在纠结为什么当我的规范通过撬动测试正常工作时,Simplecov 没有报告这个 Rake 任务。谁能指出我正确的方向?

下面的 rake 任务...

namespace :myapp do
  namespace :data do
    namespace :load do
      desc 'Enqueue a range of dates by provider'
      task range: :environment do
        cli = HighLine.new
        msg('Select the dates for your data pull. Format: yyyy-mm-dd')
        created_before = cli.ask('Data created_before? ', Date)
        created_after = cli.ask('Data created_after? ', Date)
        if created_after >= created_before
          error_msg('The created_after date must be less than created_before!')
          exit
        else
          Resque.enqueue(AmazonMws::ImportOrdersJob, created_before: created_before, created_after: created_after)
        end
      end

      desc 'Enqueue from a specified date by provider'
      task from: :environment do
        cli = HighLine.new
        msg('Select the date for your data pull. Format: yyyy-mm-dd')
        created_from = cli.ask('Data created_from? ', Date)
        Resque.enqueue(AmazonMws::ImportOrdersJob, created_from: created_from)
      end
    end
  end
end

以下规格...

describe 'rake task myapp:data:load:from' do
  include_context 'rake'
  let(:task_path) { 'tasks/data.rake' }

  before do
    ResqueSpec.reset!
  end

  describe ':range' do
    let(:created_before) { '2017-01-02' }
    let(:created_after) { '2017-01-01' }
    let(:task_name) { 'myapp:data:load:range' }
    before do
      invoke_task.reenable
      allow(highline).to receive(:ask).with('Data created_before? ', Date).and_return(created_before)
    end

    it 'exits if created_after is not >= created_before' do
      allow(highline).to receive(:ask).with('Data created_after? ', Date).and_return(created_before)
      expect { invoke_task.invoke }.to raise_error(SystemExit)
    end

    # rubocop:disable RSpec/MultipleExpectations
    it 'exits with the right message' do
      allow(highline).to receive(:ask).with('Data created_after? ', Date).and_return(created_before)

      expect do
        expect { invoke_task.invoke }.to output('The created_after date must be less than created_before!').to_stdout
      end.to raise_error(SystemExit)
    end
    # rubocop:enable all

    it 'processes from a specified starting point' do
      allow(highline).to receive(:ask).with('Data created_after? ', Date).and_return(created_after)
      invoke_task.invoke
      expect(AmazonMws::ImportOrdersJob).to have_queue_size_of(1)
    end
  end

  describe ':from' do
    let(:created_from) { '2017-01-01' }
    let(:task_name) { 'myapp:data:load:from' }
    before do
      invoke_task.reenable
      allow(highline).to receive(:ask).and_return(created_from)
    end

    it 'processes from a specified starting point' do
      # expect(Resque).to receive(:enqueue).with(AmazonMws::ImportOrdersJob, created_from: created_from)
      invoke_task.invoke
      expect(AmazonMws::ImportOrdersJob).to have_queue_size_of(1)
    end
  end
end

rake 任务的共享上下文...

shared_context 'rake' do
  let(:invoke_task) { rake[task_name] }
  let(:highline) { instance_double(HighLine) }
  let(:rake) { Rake::Application.new }

  before do
    Rake.application = rake
    load File.expand_path("#{Rails.root}/lib/#{task_path}", __FILE__)
    Rake::Task.define_task(:environment)
    allow(HighLine).to receive(:new).and_return(highline)
    # rubocop:disable all
    allow_any_instance_of(Object).to receive(:msg).and_return(true)
    allow_any_instance_of(Object).to receive(:error_msg).and_return(true)
    # rubocop:enable all
  end
end

更新

SimpleCov 使用 Ruby 标准库中的 Coverage#result module 来检查涵盖的内容。当您 re-load 使用内核 load.

文件时,Coverage#result 会重置文件(这是我的理论!)

由于您在执行每个块之前加载 data.rake,因此结果中只会报告 rspec 文件中的最后一个规范。

您可以通过使用 before(:all)

在所有示例 运行 之前加载一次任务来解决此问题

像下面这样快速更改您的共享上下文将为您提供所需的覆盖率报告。

RSpec.shared_context 'rake' do
  let(:invoke_task) { Rake.application[task_name] }
  let(:highline) { instance_double(HighLine) }

  before(:all) do
    Rake.application = Rake::Application.new
    Rails.application.load_tasks
  end    

  before do
    allow(HighLine).to receive(:new).and_return(highline)
    # rubocop:disable all
    allow_any_instance_of(Object).to receive(:msg).and_return(true)
    allow_any_instance_of(Object).to receive(:error_msg).and_return(true)
    # rubocop:enable all
  end
end