How to forcefully stop the execution of before:(all) and the corresponding it blocks in a test framework developed using Rspec?
before:(all) do
#test = check()
if #test
end
end
The check function returns true or false. If false is returned, then the corresponding examples should not get executed. How to do this?
From your description it seems like you want to stop executing tests if the check is false:
before(:all) do
unless check
puts 'Check failed, stopping test suite...'
exit
end
end
exit initiates the termination of a Ruby script by raising the SystemExit exception
Related
I am trying to write an Rspec test for my script that will pass if my script fails gracefully.
if options[:file] == false
abort 'Missing an argument'
end
Rspec:
it 'if the file argument is not given, it provides a helpful message' do
expect(`ruby example_file.rb`).to eq('Missing an argument')
end
My test continues to fail and says
expected: 'Missing an argument'
got: ''
I am not sure why it returns an empty string. I have looked at these posts with no luck:
How can I validate exit value in rspec?
How can I validate exits and aborts in RSpec?
How to spec methods that exit or abort
If you need any more information about my script let me know. Thank you.
abort/exit will both print to stderr, whereas your rspec is listening on the stdout channel. Try the following:
expect(`ruby example_file.rb`).to output('Missing an argument').to_stderr
Heroku may send a SIGTERM to your application for various reasons, so I have created a handler to take care of some cleanup in case this happens. Some googling hasn't yielded any answers or examples on how to test this in RSpec. Here's the basic code:
Signal.trap('TERM') do
cleanup
end
def cleanup
puts "doing some cleanup stuff"
...
exit
end
What's the best way to test that this cleanup method is called when the program receives a SIGTERM?
Send the signal to RSpec with Process.kill 'TERM', 0 and test that the handler is called. It's true that if the signal isn't trapped the test will crash rather than nicely reporting a failure, but at least you'll know there's a problem in your code.
For example:
class SignalHandler
def self.trap_signals
Signal.trap('TERM') { term_handler }
end
def self.term_handler
# ...
end
end
describe SignalHandler do
describe '#trap_signals' do
it "traps TERM" do
# The MRI default TERM handler does not cause RSpec to exit with an error.
# Use the system default TERM handler instead, which does kill RSpec.
# If you test a different signal you might not need to do this,
# or you might need to install a different signal's handler.
old_signal_handler = Signal.trap 'TERM', 'SYSTEM_DEFAULT'
SignalHandler.trap_signals
expect(SignalHandler).to receive(:term_handler).with no_args
Process.kill 'TERM', 0 # Send the signal to ourself
# Put the Ruby default signal handler back in case it matters to other tests
Signal.trap 'TERM', old_signal_handler
end
end
end
I merely tested that the handler was called, but you could equally well test a side effect of the handler.
Is there a Perl equivalent END block in Ruby? In Perl, if I specify an END block, the code in that block will get executed no matter where the program bails out. It is great functionality for closing open file handles. Does Ruby support similar functionality? I tried Ruby's "END{}" block but that doesnt seem to get called if I had an exit in the code due to an error.
Thanks!
Use at_exit, which will run regardless of whether an exception was raised or not:
at_exit { puts 'exited!' }
raise
prints "exited" as expected.
You should only consider this if you cannot use an ensure, as at_exit causes logic to reside far away from where the actual exit occurs.
Yes. A block may have an 'ensure' clause. Here's an example:
begin
# This will cause a divide by zero exception
puts 3 / 0
rescue Exception => e
puts "An error occurred: #{e}"
ensure
puts "I get run anyway"
end
Running this produces:
An error occurred: divided by 0
I get run anyway
I have some unit tests written using Test::Unit::TestCase, with XML generated by ci_reporter. However, due to circumstances beyond my control, they may occasionally fluctuate, and randomly fail. I'd like to detect when a test fails, and attempt to re-run it.
I tried doing this by monkey-patching 'teardown' to check 'passed?', and re-running the tests on a failure. However, the XML output will still show the first failed case, and not the second (now passing) run.
This sounds a bit like the opposite of Multiple tests with minitest
Perhaps this is a possibility: Copy your test case in an own file. As an example, try the following test:
#store it as file 'testcase.rb'
gem 'test-unit'
require 'test/unit'
class X < Test::Unit::TestCase
def test_1
num = rand(10)
assert_true( num < 2, "Value is #{num}")
end
end
Then define your test call in a rake task:
require 'rake'
TEST_REPETION = 10
task :test do
success = false
TEST_REPETION.times{
stdout = `ruby testcase.rb`
if stdout =~ /Failure/
puts "Failure occured - redo the test"
else
puts 'Tests ok'
success = true
exit
end
}
puts "Stopped after #{TEST_REPETION} tries" unless success
end
Now the test is called, until the test succeed or TEST_REPETION are done.
Remarks:
Rake isn't needed, you may do the call without rake (My template was a rake task)
This works only, if your xml changes for each run (it must be regenerated before the test. else you test always the same).
You may store the test result (stdout) in a file and use it later to analyze, which tests failed and try to retest them.
I have a rake task where I do some checks at the beginning, if one of the checks fails I would like to return early from the rake task, I don't want to execute any of the remaining code.
I thought the solution would be to place a return where I wanted to return from the code but I get the following error
unexpected return
A Rake task is basically a block. A block, except lambdas, doesn't support return but you can skip to the next statement using next which in a rake task has the same effect of using return in a method.
task :foo do
puts "printed"
next
puts "never printed"
end
Or you can move the code in a method and use return in the method.
task :foo do
do_something
end
def do_something
puts "startd"
return
puts "end"
end
I prefer the second choice.
You can use abort(message) from inside the task to abort that task with a message.
Return with an Error ❌
If you're returning with an error (i.e. an exit code of 1) you'll want to use abort, which also takes an optional string param that will get outputted on exit:
task :check do
# If any of your checks fail, you can exit early like this.
abort( "One of the checks has failed!" ) if check_failed?
end
On the command line:
$ rake check && echo "All good"
#=> One of the checks has failed!
Return with Success ✅
If you're returning without an error (i.e. an exit code of 0) you'll want to use exit, which does not take a string param.
task :check do
# If any of your checks fail, you can exit early like this.
exit if check_failed?
end
On the command line:
$ rake check && echo "All good"
#=> All good
This is important if you're using this in a cron job or something that needs to do something afterwards based on whether the rake task was successful or not.
Bonus: Return with an Error from a rescue block without the stacktrace.
By default, if you use abort inside of a rescue block, it will output the entire stack trace, even if you just use abort without re-raising the error.
To get around this, you can supply a non-zero exit code to the exit command, like:
task :check do
begin
do_the_thing_that_raises_an_exception
rescue => error
puts error.message
exit( 1 )
end
end
I tend to use abort which is a better alternative in such situations, for example:
task :foo do
something = false
abort 'Failed to proceed' unless something
end
If you need to break out of multiple block levels, you can use fail.
For example
task :something do
[1,2,3].each do |i|
...
fail "some error" if ...
end
end
(See https://stackoverflow.com/a/3753955/11543.)
If you meant exiting from a rake task without causing the "rake aborted!" message to be printed, then you can use either "abort" or "exit". But "abort", when used in a rescue block, terminates the task as well as prints the whole error (even without using --trace). So "exit" is what I use.
I used next approach suggested by Simone Carletti, since when testing rake task, abort, which in fact is just a wrapper for exit, is not the desired behavior.
Example:
task auto_invoice: :environment do
if Application.feature_disabled?(:auto_invoice)
$stderr.puts 'Feature is disabled, aborting.'
next
end