如何在RSpec中测试我加载的代码是否有任何Ruby警告?

时间:2016-02-22 19:32:01

标签: ruby rspec

有没有办法访问RSpec示例中的Ruby警告列表?我在我正在测试的库中收到以下错误,并希望为它编写单元测试。

warning: previous definition of BUILD_FILE was here

2 个答案:

答案 0 :(得分:2)

我最终启动了一个新流程并评估流程输出。在我的例子中,问题是一个重新定义的常量,所以我通过将类加载到新的Ruby进程中然后使用IO流来读取输出来进行测试:

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

答案 1 :(得分:1)

Ruby警告转到$stderr,因此您可以使用一个侦测写入警告的对象来包装它:

在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

在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

规范以

失败
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

为了方便起见,我在规范中放置了生成测试警告的行,但是对于$stderr被劫持后发出的任何警告,它应该同样有效。

我没有遇到需要在RSpec退出之前停止间谍活动,但如果你这样做就可以做到

$stderr = $stderr.__getobj__

在你想要停止间谍活动的时候。