RSpec: how to test Rails logger message expectations?
While I agree you generally don't want to test loggers, there are times it may be useful.
I have had success with expectations on Rails.logger
.
Using RSpec's deprecated should
syntax:
Rails.logger.should_receive(:info).with("some message")
Using RSpec's newer expect
syntax:
expect(Rails.logger).to receive(:info).with("some message")
Note: In controller and model specs, you have to put this line before the message is logged. If you put it after, you'll get an error message like this:
Failure/Error: expect(Rails.logger).to receive(:info).with("some message")
(#<ActiveSupport::Logger:0x007f27f72136c8>).info("some message")
expected: 1 time with arguments: ("some message")
received: 0 times
With RSpec 3+ version
Actual code containing single invocation of Rails.logger.error
:
Rails.logger.error "Some useful error message"
Spec code:
expect(Rails.logger).to receive(:error).with(/error message/)
If you want the error message to be actually logged while the spec runs then use following code:
expect(Rails.logger).to receive(:error).with(/error message/).and_call_original
Actual code containing multiple invocations of Rails.logger.error
:
Rails.logger.error "Technical Error Message"
Rails.logger.error "User-friendly Error Message"
Spec code:
expect(Rails.logger).to receive(:error).ordered
expect(Rails.logger).to receive(:error).with(/User-friendly Error /).ordered.and_call_original
Also if you care about just matching the first message and not any subsequent messages then you can use following
expect(Rails.logger).to receive(:debug).with("Technical Error Message").ordered.and_call_original
expect(Rails.logger).to receive(:debug).at_least(:once).with(instance_of(String)).ordered
Note in above variation setting .ordered
is important else expectations set start failing.
References:
http://www.relishapp.com/rspec/rspec-mocks/v/3-4/docs/setting-constraints/matching-arguments
http://www.relishapp.com/rspec/rspec-mocks/v/3-4/docs/setting-constraints/message-order