I have been battling why Simplecov is not reported this Rake task as covered when my specs work correctly via pry tests. Can anyone point me in the right direction?
The following rake task...
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
The following spec...
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
Shared context for rake tasks...
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
Updates
SimpleCov uses Coverage#result
module from Ruby standard library to check what was covered. Coverage#result
gets reset for the file (this is my theory!) when you re-load the file using Kernel load
.
Since you are loading data.rake
before each block gets executed, only the last spec in the rspec file gets reported in results.
You can fix this by loading the tasks once before the all the examples are run using before(:all)
A quick change in your shared context like below will give you the coverage report you want.
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