Include the #cause when formatting exception backtraces
Created by: hakanai
Since Ruby 2.1, Exception
has a #cause
method which shows the underlying cause of the exception. (When running on MRI, if you raise an exception from a rescue block, it sets the cause automatically. When running on JRuby, if the underlying exception came from Java, it exposes Throwable#getCause()
. The similar naming is not a coincidence - I believe it was JRuby's devs who convinced Ruby to add the feature.)
Often this contains the most useful information about the failure - the actual underlying stack which caused the test to fail, rather than a wrapped exception some higher label provided to format a nice error message.
We're currently using a trick like this to enhance ExceptionPresenter
to print this extra info:
RSpec::Core::Formatters::ExceptionPresenter.class_eval do
# Overridden to print nested causes as well as the top-level exception.
def formatted_backtrace
# Caught exception
exception = @exception
str = backtrace_formatter.format_backtrace(exception.backtrace, example.metadata)
# Cause chain
while exception.respond_to?(:cause)
exception = exception.cause
str += "--- Caused by: ---\n"
str += backtrace_formatter.format_backtrace(exception.backtrace, example.metadata)
end
str
end
end
Something like this baked into core would probably be better, but I am not sure if it makes sense in general to return it from formatted_backtrace
itself, because now it formats more than one backtrace. Maybe there should be another method which calls formatted_backtrace
once for each exception.