I have a couple rake tasks and I want to write specs for them. Yes, I should extract the programming logic from the rake tasks and encapsulate that logic into appropriate class methods. However this doesn't mean that I shouldn't be able to RSpec rake tasks.
I found an older post that got me 90% of the way to what I needed. The problem is that I suspect some sort of static file name caching is going on behind the scenes in rake so using #rake_require in an RSpec context isn't performing the functionality I was expecting. I tried moving between before :all do and before blocks, nesting describe blocks and all sorts of other craziness. I had 3 different specs and the first spec would always pass and the other two would fail; I could freely re-arrange the spec order and always the spec defined first would pass. This was maddening.
Turns out I just had to use load instead of #rake_require.
Here's what my now working spec ended up looking like, for the curious:
#./spec/lib/tasks/rake_tasks_spec.rb
require 'spec_helper'
require 'rake'
describe "rake" do
before do
@rake = Rake::Application.new
Rake.application = @rake
# previously was trying
# Rake.application.rake_require "tasks/get_comic"
load Rails.root + 'lib/tasks/get_comic.rake'
Rake::Task.define_task(:environment)
end
describe "task get_comic" do
it "should have 'environment' as a prerequisite" do
@rake['get_comic'].prerequisites.should include("environment")
end
it "works when expected input is received" do
comic = Comic.new {|c| c.comic_id = 12}
comic.should_receive(:save).and_return(true)
result = Ilk::Parser::Result.new { |r| r.comic_id = 12 }
result.should_receive(:to_model).and_return(comic)
Ilk::Parser.should_receive(:parse).with(Ilk::Constants::COMIC_URL + '12').and_return(result)
Comic.should_receive(:find_by_comic_id).with(12).and_return(nil)
@rake['get_comic'].invoke('12')
end
it "raises an error when there was a problem parsing" do
Ilk::Parser.should_receive(:parse).with(Ilk::Constants::COMIC_URL + '12').and_return(nil)
-> { @rake['get_comic'].invoke('12') }.should raise_error
end
end
end