Rake is great, but sometimes it can be a little tricky to test. I’ve bundled together some convenient helpers for RSpec to make testing Rake tasks easier.
Setup
First install Fantaskspec by adding it to you Gemfile:
group :test do gem "fantaskspec" end
Then bundle install as usual.
In your spec_helper.rb or rails_helper.rb you’ll need to require Fantaskspec:
require "fantaskspec"
Then you can make any test a Rake test by simply passing a type option to describe:
RSpec.describe "my_rake_task", type: :rake do # tests! end
I tend to make a spec file per task or namespace, depending on the size of the task(s).
Also, if you’d rather not add type: :rake to every group of Rake tests, you can tell RSpec to assume tests in spec/tasks and spec/lib/tasks are Rake specs by doing this:
RSpec.configure do |config| # ... config.infer_rake_task_specs_from_file_location! # ... end
Loading Your Rake Tasks
If you’re using Rails, simply add this to your rails_helper.rb:
Rails.application.load_tasks
If you’re in a non-Rails Ruby project you can require "rake" and also require all of your task defining files in your spec_helper.rb.
Testing
The Task
Fantaskspec naturally gives us access to the task object as the subject and task:
# spec/tasks/a_great_task_spec.rb
RSpec.describe "a_great_task", type: :rake do
it "rakes it out" do
expect(subject).to be_a(Rake::Task)
expect(subject.name).to eq("a_great_task")
expect(subject).to eq(task)
end
end
The task doesn’t need to be named in the outer most describe. You can nest them however you want and Fantaskspec will do the right thing.
# spec/tasks/some_task_spec.rb
RSpec.describe "some_task", type: :rake do
it "is some_task here" do
expect(subject.name).to eq("some_task")
end
context "other tasks" do
context "some_other_task" do
it "is some_other_task here" do
expect(subject.name).to eq("some_other_task")
end
end
end
end
If you don’t want to put the task name as the describe or context string you can always just let :task_name:
RSpec.describe "the task that does stuff", type: :rake do
let(:task_name) { "do_stuff" }
it "is do_stuff here" do
expect(subject.name).to eq("do_stuff")
end
end
Be sure to put the fully qualified task name in the describe, context, or task_name let.
RSpec.describe "a:namespaced:task", type: :rake do
it "is super namespaced" do
expect(task_name).to eq("a:namespaced:task")
end
end
Running The Task
Just call execute on the task:
it "creates an admin user" do
expect { subject.execute }.to change(AdminUser, :count).from(0).to(1)
end
Testing Dependencies
Fantaskspec gives us the handy depend_on matcher to assert our task’s dependencies:
it "depends on the Rails environment task" do
expect(subject).to depend_on(:environment)
end
# or more concisely
it { is_expected.to depend_on(:environment) }
It’s also easy to enforce multiple dependencies and their order:
it { is_expected.to depend_on(:environment, "some:other_task") }
Wrapping Up
Armed with Fantaskspec’s helpers, test driving your next Rake task will be a breeze.
DevMynd is software development companies in San Francisco with practice areas in custom mobile and web application development.