Reputation: 4080
I have the following pattern in my code:
The point is that we need errors to be silently logged, but tests need fail if there is a mistake in the code.
begin
self.a_method_call
some_other_object.a_method_that_has_been_refactored
rescue StandardError => e
Rails.logger.error e.backtrace
end
If an error is thrown because of an interaction between self.a_method_call
and some_other_object.a_method_that_has_been_refactored
then the rescue standard error will silence any error and pass any test that is testing the code block. How can I silence the rescue so that tests will fail if there is a mistake in the code in the begin clause?
Upvotes: 2
Views: 620
Reputation: 164729
Error logging is part of its functionality. Instead of silencing the rescue, capture the error logging.
As written you can do this by mocking the logger. Use with
to configure what arguments you expect Rails.logger.error
to receive. Since you don't know exactly what will be received, you can use various matchers like instance_of
to check you got what backtrace
returns, an Array.
it 'logs the backtrace as an error' do
# This comes before you call the method to set up the mock which expects
# to be called.
expect(Rails.logger).to receive(:error)
.with(instance_of(Array))
thing.some_method
end
Because this replaces Rails.logger
, if anything else in the process of thing.some_method
calls Rails.logger
the test will fail.
We can make this easier with a small refactoring. Instead of using Rails.logger
directly, make it an attribute.
class SomeClass
attr_accessor :logger
def initialize
@logger = Rails.logger
end
def some_method
a_method_call
some_other_object.a_method_that_has_been_refactored
rescue StandardError => e
logger.error e.backtrace
end
end
Now we can specifically mock what is returned from thing.logger
.
it 'logs the backtrace as an error' do
# This comes before you call the method to set up the mock which expects
# to be called.
expect(thing.logger).to receive(:error)
.with(instance_of(Array))
thing.some_method
end
Upvotes: 1