Test Rake Tasks

testing rake tasks with Rspec is not accepting arguments

So, according to this and this, the following are some ways of calling rake tasks with arguments:

Rake.application.invoke_task("my_task[arguments]")

or

Rake::Task["my_task"].invoke(arguments)

On the other hand, I was calling the task as:

Rake::Task["my_task[arguments]"].invoke

Which was a Mis combination of the above two methods.

A big thank you to Jason for his contribution and suggestion.

Testing a method defined in a rake task

You can just do this:

require 'rake'
load 'simple_task.rake'
task_needs_to_run?
=> true

I tried this myself... defining a method inside a Rake namespace is the same as defining it at the top level.

loading a Rakefile doesn't run any of the tasks... it just defines them. So there is no harm in loading your Rakefile inside a test script, so you can test associated methods.

Test Rake Tasks

Rake tasks are pretty hard to test. The easiest solution would be to move the logic into a method in an appropriate model. You can then test that and just call the method from the rake task.

writing unit test for a rake task

You've actually done the good thing here about keeping all of your task logic in a library file outside rake. I'd go a little further here...

require 'csv_importer/engine'

class WebImport
def initialize(url)
@url = url
end

def call
url = 'http://blablabla/people.csv'
csv_string = open(url).read.force_encoding('UTF-8')

string_to_users(csv_string)
end

def string_to_users(csv_string)
counter = 0
duplicate_counter = 0
....
end
end

See here that we're removed how we call our method (we don't care if it's Rake or Ruby calling our method) AND potentially separated how we get our data.

Next, I would write my test like the following:

test 'override_application' do
a = WebImport.new(url: 'http://blablabla/people.csv')

a.string_to_users("a,b,c,d,e") # <-- a string you saved from some manual run, or that contains maybe a sample record with their exact format
assert_equal Users.count, 42
end

Given that you've now seperated:

  • how you call your code, because it's away from Rake in a separate library/module
  • how your code gets it's data (normally being provided data by call... but you can insert data itself here)

Then you should be all set to go with your test driven design!

Rspec testing rake tasks

It turns out that when a rake task has been invoked it won't be ran again. You have to either reenable the task after invocation or use execute

How to test rake task when arguments are passed

It's common practice in commands to use environment variables for configuration. You'll see this used in many different gems. For your needs, you could do something like this instead:

task :do_something_after_n_number_of_days do
raise ArgumentError, 'Invalid DAYS environment setting' if ENV['DAYS'].nil?
puts ENV['DAYS']
end

Then you can set the ENV in your test, like this:

let(:task) { Rake::Task['do_something_after_n_number_of_days'] }

context "when DAYS is set" do
before { ENV['DAYS'] = '100' }

it "does something" do
expect { task.invoke }.to output("100").to_stdout
end
end

context "when DAYS is nil" do
before { ENV['DAYS'] = nil }

it "raises an ArgumentError" do
expect { task.invoke }.to raise_error(ArgumentError, /Invalid DAYS/)
end
end

How to write unit test cases for rake tasks in rails?

What you can do is this..

  1. Write your logic which will run on a rake task inside a model or class.

  2. Write unit test for that model.

  3. Finally call that method inside your rake task.

Running Rake tasks in Rspec Tests

You can invoke Rake tasks as following:

require 'rake'
Rake::Task[name].invoke

In this case this would result in the following code:

require 'rake'
Rake::Task['db:test:purge'].invoke

Order of Rake Test Task

Found the Bug - This problem was not ruby / rake specific. The flash_application task changes the working directory. Because of that, there is no Rakefile with a task 'hardware' in the current working directory. But researching for this bug yielded some interesting insights.

  • Ruby arrays are ordered, if one want to execute task in an order it is sufficient to define them in execution order in an array i.e.

    task some_task: [:first, :second, :third]

  • Rake::TestTask.new defines a plain old rake task when called. That means, when rake is called, ruby creates an instance of a Rake::TestTask. All code passed into the constructor is executed / yielded during this phase. This yields the described behavior from the original question.



Related Topics



Leave a reply



Submit