chief7
chief7

Reputation: 14383

How can I test in RSpec whether code I've loaded has any Ruby warnings?

Is there any way to access the list of Ruby warnings inside an RSpec example? I am receiving the following error in a library I'm testing and want to write a unit test for it.

warning: previous definition of BUILD_FILE was here

Upvotes: 3

Views: 159

Answers (2)

chief7
chief7

Reputation: 14383

I ended up initiating a new process to and evaluate the process output. In my case the issue was a redefined constant so I'm testing by loading the class twice into the new Ruby process and then using IO stream to read the output:

it 'should not redefine BUILD_FILE constant' do
    root_path = "#{File.dirname(__FILE__)}/../../../../"
    cmd = "load \"#{root_path}libraries/build_file.rb\";"
    ruby_path = 'C:/opscode/chefdk/embedded/bin/ruby.exe'

    pipe_cmd_in, pipe_cmd_out = IO.pipe
    pid = Process.spawn("#{ruby_path} -e '#{cmd} #{cmd}'", :out => pipe_cmd_out, :err => pipe_cmd_out)
    Process.wait(pid)
    pipe_cmd_out.close
    output = pipe_cmd_in.read
    puts "OUTPUT = #{output}"

    expect(output).to_not match(/previous\sdefinition\sof\sBUILD_FILE/)
end

Upvotes: 2

Dave Schweisguth
Dave Schweisguth

Reputation: 37607

Ruby warnings go to $stderr, so you can wrap it with an object that spies on warnings written to it:

In spec/support/warning_spying_stderr.rb:

require 'delegate'

class WarningSpyingIO < SimpleDelegator
  attr_reader :strings

  def initialize(delegate)
    @strings = []
    super
  end

  def write(string)
    if string.include? 'warning: ' # in case anything other than a Ruby warning goes to $stderr
      @strings << string
    end
    __getobj__.write string
  end

end

$stderr = WarningSpyingIO.new $stderr

In spec/warning_spec.rb:

describe "My code" do
  it "has no warnings" do
    FOO = 'foo'
    FOO = 'bar'
    expect($stderr.strings).to be_empty
  end
end

The spec fails with

expected `[
  "spec/warning_spec.rb:4: warning: already initialized constant FOO\n", 
  "spec/warning_spec.rb:3: warning: previous definition of FOO was here\n"
].empty?` to return true, got false

I put the line that generates the test warning in the spec for convenience, but it should work equally well for any warning issued after $stderr is hijacked.

I didn't encounter a need to stop spying before RSpec exited, but if you do you can do

$stderr = $stderr.__getobj__

at the point at which you want to stop spying.

Upvotes: 1

Related Questions