I use rufus scheduler to run overnight test scripts by calling my functions.
Sometimes I can see "scheduler caught exception:" a message that threw some of my functions. Then scheduler stops execution of following test cases.
How can I make it so scheduler runs all test cases regardless of any exception caught?
This is called "exception swallowing". You intercept an exception and don't do anything with it.
begin
# do some dangerous stuff, like running test scripts
rescue => ex
# do nothing here, except for logging, maybe
end
If you do not need to do anything with the exception, you can omit the => ex:
begin
# do some dangerous stuff, like running test scripts
rescue; end
If you need to rescue Exceptions that don't subclass from StandardError, you need to be more explicit:
begin
# do some dangerous stuff, like running test scripts
rescue Exception
# catches EVERY exception
end
I will sometimes use the fact that you can pass blocks to a method, and I have the method rescue errors, and my code can continue on its way.
def check_block
yield
rescue NoMethodError => e
<<-EOR
Error raised with message "#{e}".
Backtrace would be #{e.backtrace.join('')}
EOR
end
puts check_block {"some string".sort.inspect}
puts check_block {['some', 'array'].sort.inspect}
This first block will go through and rescue with a report returned, the second will operate normally.
This rescue only rescues NoMethodError while you may need to rescue other errors.
Related
Suppose you have an existing app, and want to modify the exception handling for the entire app. It is not possible to wrap the app in a begin/rescue block.
What is a good way to modify the exception handler (to suppress the backtrace) by adding code that runs before the app starts?
begin/rescue are not methods so you can't over-write them. If an exception is raised, several steps will unfold, the first one being...calling .exception on whatever object you passed the exception on. Example:
class A
def exception
p 'I am going to print'
RuntimeError.new('message')
end
end
a = A.new
raise a #=> 'I am going to print' and then runtime error is raised
If you control what you pass to 'raise', then you can pass it an object. The first step after .raise is called is that it calls the .exception method on that object, as you can see from here.
If you don't want the backtrace to show at all in the terminal, use abort instead of raise:
abort 'aborting!' #=> prints 'aborting' to STDERR and then does exit 1 implicitly. No backtrace is shown.
You can wrap the entire app in a method that will do all the exception handling for you:
def exception_handler
puts 'Do whatever you want here before the app starts executing'
yield
rescue
# put the logic of handling errors here
# for example, you could do 'abort 'error occured'' that will make the program stop and not show a backtrace
end
exception_handler do
puts 'My app code goes here'
end
Will print:
Do whatever you want here before the app starts executing
My app code goes here
Let's say your app raises a bunch of ArgumentErrors. What you can do is re-open the class and execute some code before raising:
class ArgumentError
alias_method :real_initialize, :initialize
def initialize(*args) # we're overriding initialize
super(*args)
p 'some code here'
end
end
raise ArgumentError
Recently, I am working on mobile automation using appium+selenium in ruby. But stopped by the following issue: selenium driver is quit automatically (mobile app is closed) every time an exception happens. This will result in that the following code to access the driver will fail after I manage to rescue the exception.
e.g.
begin
#driver.find_element(:xpath, "//window[1]/button[27]")
rescue
#driver.find_element(:xpath, "//window[1]/navigationBar[1]/button[2]").click
end
Does anyone have this issue as well?
According to http://www.ruby-doc.org/core-2.1.1/doc/syntax/exceptions_rdoc.html "By default StandardError and its subclasses are rescued. You can rescue a specific set of exception classes (and their subclasses) by listing them after rescue:
begin
# ...
rescue ArgumentError, NameError
# handle ArgumentError or NameError
end
I assume you are waiting for something like ElementNotVisibleException. So, add type of exception after rescue. Something like rescue ElementNotVisibleException.
The problem is in relation to the radis-rb gem.
The exception is not caught by my rescue block and my app goes down.
My code:
begin
redis = Redis.new
puts "WTF?"
rescue Exception
puts "Exception"
end
If redis is down, the message WTF? is exposed.
It happens with or without the Exception statement.
Why is the exception not raised to my rescue block?
I have solved the problem myself (with help from the community and comments).
The exception occurred in IRB only.
The reason of one is IRB's inspect call when IRB try to print result of Redis.new.
In the script (not IRB), the exception doesn't occur because Redis.new does not raise an exception if the Redis service is down.
This question helped to solve my problem.
I have a set of cucumber tests that get run on a build server.
I often want faster feedback than the server directly provides and so I watch the console output as it runs. I was wanting a way of identifying any failing test with a single search term so I modified our Around to print "Failed Test" on any exception, but Ruby doesn't seem to be handing the exception back up to the around. I've verified this by having puts statements after the begin ... end.
Does anyone know why this is happening or a way of wrapping any exception thrown from a failing test in a begin?
Around() do |scenario, block|
begin
Timeout.timeout(0.1) do
block.call
end
rescue Timeout::Error => e
puts "Failed Test"
puts caller
rescue Exception => e
puts "Failed Test"
raise e
end
end
Looking at cucumber 1.3.12 it actually rescues any exceptions from scenario steps. So you can't see them in any way without modifying cucumber gem.
See my answer on how to put a debug hook in that place for more information:
https://stackoverflow.com/a/22654786/520567
Have you tried disabling Cucumber's exception capturing with the #allow-rescue tag?
#allow-rescue: Turns off Cucumber’s exception capturing for the tagged scenario(s). Used when the code being tested is expected to raise and handle exceptions.
https://github.com/cucumber/cucumber/wiki/Tags
What is the difference - technical, philosophical, conceptual, or otherwise - between
raise "foo"
and
raise Exception.new("foo")
?
Technically, the first raises a RuntimeError with the message set to "foo", and the second raises an Exception with the message set to "foo".
Practically, there is a significant difference between when you would want to use the former and when you want to use the latter.
Simply put, you probably want a RuntimeError not an Exception. A rescue block without an argument will catch RuntimeErrors, but will NOT catch Exceptions. So if you raise an Exception in your code, this code will not catch it:
begin
rescue
end
In order to catch the Exception you will have to do this:
begin
rescue Exception
end
This means that in a sense, an Exception is a "worse" error than a RuntimeError, because you have to do more work to recover from it.
So which you want depends on how your project does its error handling. For instance, in our daemons, the main loop has a blank rescue which will catch RuntimeErrors, report them, and then continue. But in one or two circumstances, we want the daemon to really really die on an error, and in that case we raise an Exception, which goes straight through our "normal error handling code" and out.
And again, if you are writing library code, you probably want a RuntimeError, not an Exception, as users of your library will be surprised if it raises errors that a blank rescue block can't catch, and it will take them a moment to realize why.
Finally, I should say that the RuntimeError is a subclass of the StandardError class, and the actual rule is that although you can raise any type of object, the blank rescue will by default only catch anything that inherits from StandardError. Everything else has to be specific.
From the offical documentation:
raise
raise( string )
raise( exception [, string [, array ] ] )
With no arguments, raises the exception in $! or raises a RuntimeError if $! is nil. With a single String argument, it raises a RuntimeError with the string as a message. Otherwise, the first parameter should be the name of an Exception class (or an object that returns an Exception when sent exception). The optional second parameter sets the message associated with the exception, and the third parameter is an array of callback information. Exceptions are caught by the rescue clause of begin...end blocks.
raise "Failed to create socket"
raise ArgumentError, "No parameters", caller