Testing rake tasks with rspec doesn't seem to work - ruby

I'm trying to test a very simple rake task with rspec, but I'm finding it very difficult and whatever change I do my tests don't seem to fail...
This is the task I'm trying to test:
desc 'Outputs the current version of Rivendell'
task version: :environment do
puts Rivendell::VERSION
end
As you can see, it's a very basic task.
This is my test:
describe 'Rakefile' do
before :each do
Rake.application.rake_require File.expand_path(
'../../Rakefile', File.dirname(__FILE__))
Rake::Task.define_task :environment
end
describe 'rivendell::version' do
let :run_rake_task do
Rake::Task["rivendell::version"].reenable
Rake.application.invoke_task "rivendell::version"
end
it 'should display the right version' do
Rivendell.should_receive('VERSION')
run_rake_task
end
end
All tests for some reason pass, but if I change the should_receive call to
Rivendell.should_receive('DOESNTEXIST')
All tests pass in any case.
What am I doing wrong here?

Related

How to fetch RSpec test name in before(:each) block without a spec_helper

So here's an example basic test suite:
describe "Main test suite" do
it "should run test #1" do
...
end
it "should run test #2" do
...
end
end
I want to add a before(:each) which does some special logic with the full test name (it'll be inserting the test name as a metadata header into all of the HTTP requests made by each test). I've found that using "#{self.class.description}" only captures the test suite name ("Main test suite" in this case), but I also need to capture the test name itself.
I've seen some other similar questions on StackOverflow such as Getting the full RSpec test name from within a before(:each) block, but the answers all involve adding Spec::Runner.configure or RSpec.configure options to the spec_helper.rb, but we're running these tests through a custom environment which doesn't use a spec_helper.rb, so I need a solution that doesn't depend on that.
I've also seen other examples such as How to get current context name of rspec where they are doing the logging in the test itself instead of in a before(:each) block, so they can just do something like: it "should Bar" do |example| puts "#{self.class.description} #{example.description}" end. But we have hundreds of these tests and I don't want to copy-paste the same logic in every test -- this seems like an ideal use case for a before(:each) block.
describe "Main test suite" do
before(:each) do |x|
puts "#{x.class.description} - #{x.example.description}"
end
it "should run test #1" do
...
end
it "should run test #2" do
...
end
end
I got it working by putting this at the top of my file:
RSpec.configure do |config|
config.before(:each) do |x|
do_stuff("#{x.class.description} - #{x.example.description}")
end
end

Why undefined method `expect' when checking in at_exit hook

I am trying to check the exitstatus of a command through the below code. It is resulting in an error --->undefined method 'expect'
require 'rspec'
require 'rspec/expectations'
at_exit do
\`cat /etc/redhat-release\`
expect($?.exitstatus).to eq(0)
end
Can any one please help me in solving this problem
Your code is suppose be a test case based on rspec, and you are mixing it with normal ruby code.
In order to test your code with rspec you need to wrap the test scenarios and cases inside a describe and it block, only then you'll have access to the expect method, like so:
# test.rb
require 'rspec'
require 'rspec/expectations'
describe 'Test exit status' do
it "check status" do
`cat /etc/redhat-release`
expect($?.exitstatus).to eq(0)
end
end
and you run this code with rspec command line, like: rspec test.rb
The code you had before, was using the at_exit block. This is only called when you exit the program, or receive a signal for it to be killed.

Invoking the same rake task twice in RSpec

I am trying to test a rake task with rspec, and for that purpose I need to invoke it twice but
it is only being invoked once.
it 'first test' do
Rake::Task['my_rake_task'].invoke
# rake task was processed
end
it 'second test' do
Rake::Task['my_rake_task'].invoke
# rake task was NOT processed
end
if a rake task has already been invoked once it won't run again unless you call:
#rake[#task_name].reenable
or invoke it with
#rake[#task_name].execute
To adding to Guy Segev answer I prefer adding this to your spec file
after(:each) do
Rake::Task["task:name"].reenable
end

Running minitest handler tests inside another ruby script

I'd like to run my minitest handler tests inside another ruby script (a bootstrapper script of sorts). I'd like to return the results of my tests to a variable that I can then parse to make sure everything passed before moving on. Is this possible? If so, what does the syntax for something like this look like?
You can shell out to run the test and capture the output.
puts "Running foo test:"
output = `ruby -Ilib:test test/test_foo.rb`
puts output
puts "Completed foo test."
Okay so I figured out how to do this using the rake::test library. This code will execute a minitest test, then slurp in the xml from the report and determine if everything passed or not.
require 'rake'
require 'rake/testtask'
require 'ci/reporter/rake/minitest'
require 'xmlsimple'
Rake::TestTask.new do |t|
t.verbose = true
t.test_files = FileList['system_tests/vm_tests.rb']
end
task :test => :"ci:setup:minitest"
Rake::Task[:test].execute
results = XmlSimple.xml_in('test/reports/TEST-VMtests.xml')
if results["failures"] > 0 or results["errors"] > 0
raise "The VM Tests have resulted in failures or errors"
end

How do I run Rake tasks within a Ruby script?

I have a Rakefile with a Rake task that I would normally call from the command line:
rake blog:post Title
I'd like to write a Ruby script that calls that Rake task multiple times, but the only solution I see is shelling out using `` (backticks) or system.
What's the right way to do this?
from timocracy.com:
require 'rake'
def capture_stdout
s = StringIO.new
oldstdout = $stdout
$stdout = s
yield
s.string
ensure
$stdout = oldstdout
end
Rake.application.rake_require 'metric_fetcher', ['../../lib/tasks']
results = capture_stdout {Rake.application['metric_fetcher'].invoke}
This works with Rake version 10.0.3:
require 'rake'
app = Rake.application
app.init
# do this as many times as needed
app.add_import 'some/other/file.rake'
# this loads the Rakefile and other imports
app.load_rakefile
app['sometask'].invoke
As knut said, use reenable if you want to invoke multiple times.
You can use invoke and reenable to execute the task a second time.
Your example call rake blog:post Title seems to have a parameter. This parameter can be used as a parameter in invoke:
Example:
require 'rake'
task 'mytask', :title do |tsk, args|
p "called #{tsk} (#{args[:title]})"
end
Rake.application['mytask'].invoke('one')
Rake.application['mytask'].reenable
Rake.application['mytask'].invoke('two')
Please replace mytask with blog:post and instead the task definition you can require your rakefile.
This solution will write the result to stdout - but you did not mention, that you want to suppress output.
Interesting experiment:
You can call the reenable also inside the task definition. This allows a task to reenable himself.
Example:
require 'rake'
task 'mytask', :title do |tsk, args|
p "called #{tsk} (#{args[:title]})"
tsk.reenable #<-- HERE
end
Rake.application['mytask'].invoke('one')
Rake.application['mytask'].invoke('two')
The result (tested with rake 10.4.2):
"called mytask (one)"
"called mytask (two)"
In a script with Rails loaded (e.g. rails runner script.rb)
def rake(*tasks)
tasks.each do |task|
Rake.application[task].tap(&:invoke).tap(&:reenable)
end
end
rake('db:migrate', 'cache:clear', 'cache:warmup')

Resources