Hi there,
we have some rake tasks including specs. Unfortunately we do not get code coverage for these rake tasks. Maybe it's an issue of the file extension .rake. Is there a possibility to include .rake files?
Unrelated to your problem, it's a best practice not to test Rakefiles. Any code that you'd put in a rakefile should call out to something in e.g. lib that you test.
SimpleCov just uses the Ruby stdlib Coverage module. Since Rakefiles are Ruby, they should be included unless either they are filtered out by location or are loaded before SimpleCov.start.
If you have any more questions, please paste your simplecov config, how you run your tests, your simplecov version, your ruby, your rake file location, and where you require simplecov.
If you solve you problem, please write up what helped and close the issue. Thanks :)
Please also review https://github.com/colszowka/simplecov/blob/master/CONTRIBUTING.md and https://github.com/colszowka/simplecov/issues/340
I'm running into this issue: I'm using SimpleCov with rspec and cucumber and a shared .simplecov file.
# .simplecov
SimpleCov.start do
use_merging true
merge_timeout 20 * 60
coverage_dir 'doc/build/coverage'
add_filter '/spec/'
add_filter '/vendor/'
add_filter '/config/'
add_group 'Libraries', 'lib'
add_group 'Controllers', 'app/controllers'
add_group 'Models', 'app/models'
add_group 'Helpers', 'app/helpers'
add_group 'Services', 'app/services'
add_group 'Mailers', 'app/mailers'
add_group 'Views', 'app/views'
add_group 'Workers', 'app/workers'
end
# spec_helper.rb
ENV["RAILS_ENV"] ||= 'test'
#Conditionally enable simplecov
if ENV["COVERAGE"]
require 'simplecov'
end
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
# etc
There's a similar setup in the cucumber files, but it doesn't affect this at all.
The specs in question use the methodology from thoughtbot:
require "rake"
shared_context "rake" do
let(:rake) { Rake::Application.new }
let(:task_name) { self.class.top_level_description }
let(:task_path) { "lib/tasks/#{task_name.split(":").first}" }
subject { rake[task_name] }
def loaded_files_excluding_current_rake_file
$".reject {|file| file == Rails.root.join("#{task_path}.rake").to_s }
end
before do
Rake.application = rake
Rake.application.rake_require(task_path, [Rails.root.to_s], loaded_files_excluding_current_rake_file)
Rake::Task.define_task(:environment)
end
end
And the tests look like this:
describe 'namespace:task_name' do
include_context 'rake'
it 'does something helpful' do
SomeClass.should_receive(:method).with('args')
subject.invoke
end
end
Generally only whichever task is last run from a file in the spec is shown as covered by SimpleCov.
So if the .rake file looked like this:
```ruby
namespace :namespace do
desc 'first task'
task :first => :environment do
thing_to_test
end
desc 'second task'
task :second => :environment do
thing_to_test
end
end
And rspec ran the tests like:
namespace:second
does something
namespace:first
does something
Only the first task would show green on the line with thing_to_test. The second would show it wasn't covered, even though the test had run successfully.
I'm not tied to the implementation from Thoughtbot, though it'd take some work to research and figure out an alternative if that's what's causing the problem.
Any thoughts would be helpful.
Hi there,
without digging too deep into the thoguhtbot way there it seems like it would reload files, which messes with coverage.
I can just echo the thoughts of @bf4 - just make the rake task call out to something else and test that.
task :first => :environemnt do
MyServiceObject.new(some_parameter).call
end
then test MyServiceObject that should all be coverd neatly :)
Has anyone figured out how to get coverage on vanilla rake tasks?
My setup is largely based on the great 2011 guide: https://robots.thoughtbot.com/test-rake-tasks-like-a-boss
My tasks are more than a trigger for some other method. Here's an example:
namespace :import do
desc "Import Photos from Wordpress"
task photos: :environment do |task|
log = ProcessLog.create(key: task.to_s)
begin
Parallel.each(Person.active, in_processes: MAX_PROCESSES) do |person|
person.import_photo
end
rescue => e
log.fail!(comment: e.to_s)
end
log.success!
end
end
I'm logging when the task was run, how long it took, if it failed and with what error message. I could create a class method on Person or a service object as discussed above, but the logic of import_photo is tested elsewhere already anyway.
I want to test that the task actually works before it fails in production. I also test that all my tasks have the desc line so they'll show up in rake -T That really only fits in a task spec...
I test my tasks fully, but sure would like to be able to show it.

My original solution here worked, but I ran into problems with coverage results getting clobbered by subsequent tasks specs. One of those _you get results for the last test_ situations. I solved it by moving the task loading out of the shared_context entirely, so it's only ever executed once.
spec/support/shared_contexts/rake.rb
# https://github.com/colszowka/simplecov/issues/369
shared_context "rake" do
let(:task_name) { self.class.top_level_description }
subject { Rake.application[task_name] }
# This allows tasks to be invoked more than once.
before do
subject.reenable
end
end
spec/rails_helper.rb
require 'simplecov'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
# Load rake tasks so they can be tested.
Rake.application = Rake::Application.new
Rails.application.load_tasks
...

Most helpful comment
SOLVED - UPDATED
My original solution here worked, but I ran into problems with coverage results getting clobbered by subsequent tasks specs. One of those _you get results for the last test_ situations. I solved it by moving the task loading out of the shared_context entirely, so it's only ever executed once.
spec/support/shared_contexts/rake.rb
spec/rails_helper.rb