When you need to test Rake tasks for a Rails app, its convenient to be able to write short, snappy specs like so:
# File: spec/tasks/send_invoices_spec.rb
require "rails_helper"
describe "rake billing:send_invoices", type: :task do
it "preloads the Rails environment" do
expect(task.prerequisites).to include "environment"
end
it "runs gracefully with no subscribers" do
expect { task.execute }.not_to raise_error
end
it "logs to stdout" do
expect { task.execute }.to output("Sending invoices\n").to_stdout
end
it "emails invoices" do
subscriber = create(:subscriber)
task.execute
expect(subscriber).to have_received_invoice
end
it "checks in with Dead Mans Snitch" do
dead_mans_snitch_request = stub_request(:get, "https://nosnch.in/c2354d53d2")
task.execute
expect(dead_mans_snitch_request).to have_been_requested
end
matcher :have_received_invoice do
match_unless_raises do |subscriber|
expect(last_email_sent).to be_delivered_to subscriber.email
expect(last_email_sent).to have_subject 'Your invoice'
...
end
end
end
To be able to do this for your project, create the following file spec/support/tasks.rb
(ensuring its require
-d by rails_helper.rb
or spec_helper.rb
):
# File: spec/support/tasks.rb
require "rake"
# Task names should be used in the top-level describe, with an optional
# "rake "-prefix for better documentation. Both of these will work:
#
# 1) describe "foo:bar" do ... end
#
# 2) describe "rake foo:bar" do ... end
#
# Favor including "rake "-prefix as in the 2nd example above as it produces
# doc output that makes it clear a rake task is under test and how it is
# invoked.
module TaskExampleGroup
extend ActiveSupport::Concern
included do
let(:task_name) { self.class.top_level_description.sub(/\Arake /, "") }
let(:tasks) { Rake::Task }
# Make the Rake task available as `task` in your examples:
subject(:task) { tasks[task_name] }
end
end
RSpec.configure do |config|
# Tag Rake specs with `:task` metadata or put them in the spec/tasks dir
config.define_derived_metadata(:file_path => %r{/spec/tasks/}) do |metadata|
metadata[:type] = :task
end
config.include TaskExampleGroup, type: :task
config.before(:suite) do
Rails.application.load_tasks
end
end
Source: https://github.com/eliotsykes/rails-testing-toolbox/blob/master/tasks.rb
Now write your task specs in the spec/tasks/
directory like the example
send_invoices_spec.rb
given earlier, in which you will be able to call:
task.execute
to run the tasktask.prerequisites
to access the tasks thattask
depends ontask.invoke
to run the task and its prerequisite tasks