Rake vs. RSpec! Fight!
I love RSpec, and lately I’ve been making the transition from test-friendly development to full-on spec-driven development. I still toss around some code for proofs of concept or to prototype APIs, but when the time comes to write serious code, I always begin with a spec.
I was working on a project recently which boiled down to “run these tasks in this order,” which is a natural fit for Rake. I have lots of beef with Rake, but I was able to back away from the yak-shaving precipice with this:
def describe_rake_task(task_name, filename, &block)
require "rake"
describe "Rake task #{task_name}" do
attr_reader :task
before(:all) do
@rake = Rake::Application.new
Rake.application = @rake
load filename
@task = Rake::Task[task_name]
end
after(:all) do
Rake.application = nil
end
def invoke!
for action in task.instance_eval { @actions }
instance_eval(&action)
end
end
instance_eval(&block)
end
end
Drop that in your spec_helper.rb and you can do stuff like this:
describe_rake_task "build:my_thing", "lib/tasks/my_thing.rake" do
it "should build my other thing first" do
task.prerequisites.should include("build:my_other_thing")
end
it "should do something" do
@built_my_thing = false
Builder.should_receive(:build).with(:my_thing)
invoke!
@built_my_thing.should be(false)
end
end
Which, when run, produces this:
Rake task build:my_thing
- should build my other thing first
- should do something
The invoke! method runs the task’s action(s) inside the spec’s instance, which means you can mock out methods and handle changes to instance variables.
Doesn’t much change my opinion of Rake, but at least I’ve got a better way to write tasks for it.
4 comments »