Reputation: 14383
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
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
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