Happy Thanksgiving!

I am testing an application that reports all errors through a common 
interface, which then distributes errors to various loggers (rails logs, 
logentries, etc).  Each reporter logs messages based on severity and 
environment.  In our test environment, the generic logging interface is set 
to always re-raise reported errors such that tests will always fail if an 
error is reported through this interface that is not expected.  In the 
majority of cases, this means that conditions where such errors would 
normally be reported, handled and swallowed in production will instead 
re-raise the exception (in test) and ultimately cause the test to fail if 
the error is not explicitly expected.

However, we still observe conditions where:

   1. class A calls class B calls class C.
   2. class C raises an exception.
   3. class B catches said exception and logs it via the Logger.
   4. The Logger re-raises the error.
   5. class A catches the re-raised error but swallows it completely.
   6. The test passes if there are no failing expectations as a result, 
   even though an exception occurred.

Is there some way to report errors to rspec via a sideband messaging 
channel, such that we can implement a logger that would simply report 
errors directly to rspec and bypass the need for an exception to bubble all 
the way up to the top of the stack in order for a test to fail?

The only possible solution I know of so far would be to set a global 
expectation for the logging class not to receive an error message, and 
override that behavior in individual tests; however, this feels like the 
wrong solution and I'm not sure it would actually work as desired to modify 
the expectation behavior from `expect().not_to receive` (in a global before 
hook) to `allow().to receive`, or `expect().to receive`.  Or we would have 
to override the default expectation via metadata in individual tests which 
again is not an ideal solution.

Here is a rudimentary example of the problem:

class RSpecLogger
  def error(e)
    # somehow report sideband error to rspec
  end
end

class SomeOtherReporter
  def error(e)
    puts e.message
  end
end

class MyErrorLogger
  LOGGERS = [
    SomeOtherReporter.new,
    RSpecLogger.new
  ]

  def self.error(exception)
    LOGGERS.each { |r| r.error(exception) }

    raise exception if should_reraise? # This could be replaced entirely 
via sideband reporting
  end

  def self.should_reraise?
    true # if in test environment
  end
end

describe MyErrorLogger do
  it 'should fail even if reraise is caught elsewhere' do
    begin
      begin
        # Something raises an exception
        raise StandardError.new("Foo message")
      rescue => e
        # We rescue and log it
        described_class.error(e)
      end
    rescue => e
      # the reraised error is swallowed somewhere further up the stack, so 
the test passes if no assertions fail.
      nil
    end
  end
end

Thanks,
Tim

-- 
You received this message because you are subscribed to the Google Groups 
"rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/rspec/d0fcb0da-8578-49f0-be1e-9a9094276fe0%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to