6

I have an non-rails ruby application, that uses logger to handle log output to stdout.
I want to add specs for checking that output and found two ways to implement this and seems both ways don't work.

So both ways are in this spec.rb file:

require 'rspec' 
require 'logger'

describe 'Logger' do   
  it 'expect to output' do
    expect { Logger.new(STDOUT).info('Hello') }.to output.to_stdout    
  end

  it 'expect to recieve' do
    expect(Logger.new(STDOUT).info('Hello')).to receive(:info)   
  end 
end

I have output to terminal with log messages, but both verification are failed

2 Answers 2

5

Replace STDOUT with $stdout. This works:

expect { Logger.new($stdout).info('Hello') }.to output.to_stdout

The reason is that Rspec internally modifies the global variable $stdout to capture its contents with an StringIO. When using the constant, this mechanism does not work because STDOUT keeps the original value of $stdout.

Notice that you will have a similar problem is you initialize the logger outside of the block. The logger object will store internally the original reference and it won't work:

logger = Logger.new($stdout)
expect { logger.info('Hello') }.to output.to_stdout # This won't work

As per the second question:

expect(Logger.new(STDOUT).info('Hello')).to receive(:info)   

This is just a wrong usage of Rspec. It should be something like:

logger = Logger.new(STDOUT)
expect(logger).to receive(:info)   
logger.info("Hello")
Sign up to request clarification or add additional context in comments.

Comments

2

I typically just use doubles like this:

describe 'logging' do
  it 'handles output' do
    logger = double('logger')
    allow(Logger).to receive(:new).and_return(logger)

    run_some_code
    expect(logger).to receive(:info).with("Hello")
  end
end

4 Comments

Looks like a pretty non-straightforward workaround, it's quite hard for me to understand how it works. I hope there is a better way
Well you don't need to test that the logger class is actually doing it's job, you just want to ensure you're use of the logger class is outputting your specific message. This is the best way to do it IMO.
@Anthony, what if you subclass Logger and override info, like I did? Then you need to test it, otherwise your test coverage won't be 100%.
@WilsonSilva then you'd need unit tests for your overrides not for the Logger parent class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.