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.
load
ing a Rakefile doesn't run any of the tasks... it just defines them. So there is no harm in load
ing 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 invoke
d 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..
Write your logic which will run on a rake task inside a model or class.
Write unit test for that model.
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
Rails: I Can't Call a Function in a Module in /Lib - What am I Doing Wrong
Capistrano & Bash: Ignore Command Exit Status
Collect Values from an Array of Hashes
Confusing Behaviour of Const_Get in Ruby
Check Ruby Http Response for Success
Understanding Io.Select When Reading Socket in Ruby
Convert String to Decimal Number in Ruby
What Does the % Operator Do in Ruby in N % 2
Unicorn Unable to Write Pid File
How to Match Unicode Words with Ruby 1.9
Building a Hash in a Conditional Way
Ruby Koan 151 Raising Exceptions
How to Run a Ruby Script Within Bundler Context
Ruby on Rails, Including a Module with Arguments