(apparently) identical tests for two rake tasks; only one passes
Nutshell: Change your before
to a before :all
(instead of :each
).
Or: Pass an empty array as a third parameter to rake_require
.
Rake.application.rake_require 'lib/tasks/demo_tasks',
[Rails.root.to_s],
[]
Details
def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
fn = file_name + ".rake"
return false if loaded.include?(fn)
...
$"
is a Ruby special variable that holds an array of modules loaded by require
.
If you don't pass the optional parameter, rake_require
will use that array of modules loaded by Ruby. This means the module won't be loaded again: Ruby knows the module was loaded, rake checks to see what Ruby knows, and it's a new rake instance for each test.
Switching to before :all
worked because it meant the let
block only ran once: one rake instance, one module load, everybody is happy.
All this said, why reload the rake environment twice anyway? Your goal is to test your tasks, which doesn't require a fresh rake context for every spec.
You could eliminate the local altogether at the cost of some minor verbosity in each spec:
describe "test tasks" do
before :all do
Rake.application = Rake::Application.new
Rake.application.rake_require 'lib/tasks/demo_tasks', [Rails.root.to_s]
Rake::Task.define_task :environment
end
describe "demo:test" do
it "runs" do
Rake::Task["demo:test"].invoke
end
end
end
You could define an instance variable in the before
block to avoid the Rake::Task
reference:
before :all do
@rake = Rake::Application.new
Rake.application = @rake
Rake.application.rake_require 'lib/tasks/demo_tasks', [Rails.root.to_s]
Rake::Task.define_task :environment
end
describe "demo:test" do
it "runs" do
@rake["demo:test"].invoke
IMO, less desirable for a number of reasons. Here's a summary I agree with.