我可以在RSpec中存根STDERR吗?

时间:2012-04-11 15:13:09

标签: ruby rspec stub

我有一个简单的功能,我想测试(也许主要是为了安抚simplecov)。功能是:

module Utils
  extend self

  def blather(msg)
    msg = "=== " + msg
    STDERR.puts(msg)
    Rails.logger.debug(msg)
  end

end

RSpec documentation for stubbing说:

  

消息可以存储在任何类上,包括Ruby核心库中的消息。

但是以下内容:

# file: spec/lib/utils_spec.rb
require 'spec_helper'
describe Utils do
  context "blather" do
    it "should print to STDERR" do
      STDERR.any_instance.should_receive(:puts).with("=== zoo")    
      Utils.blather("zoo")
    end
  end
end

...我收到错误

undefined method `any_instance' for #<IO:<STDERR>>

不考虑此测试是否有意义,是否可以存根STDERR(IO类)?这是失败的,因为它是一种类方法吗?或者这种测试是否有更明智的策略?

3 个答案:

答案 0 :(得分:6)

首先,您通常应使用$stderr而不是STDERR

module Utils
  extend self

  def blather(msg)
    msg = "=== " + msg
    $stderr.puts(msg)
    Rails.logger.debug(msg)
  end

end

要回答您的问题,您可以在RSpec中执行以下操作:

describe Utils do
  context "blather" do
    it "should print to stderr" do
      $stderr.should_receive(:puts).with("=== zoo")
      Utils.blather("zoo")
    end
  end
end

您只需通过$stderr.should_receive存根该方法即可。因为$stderr是一个普通的对象,所以你可以像平常那样存在方法,并设置它的期望值。

答案 1 :(得分:2)

有很多方法可以写入stderr,因此测试结果字符串通常更好,而不是要求puts使用特定参数调用一次。

只要您的函数使用$stderr(旨在改变)而不是STDERR const,您就可以使用rspec的漂亮output matcher

expect { blather("zoo") }.to output(/=== zoo/).to_stderr

如果您需要更多控制权,可以使用$stderr实例替换stub_const "STDERR"(可能还有StringIO),然后再对其.string进行断言... (这是输出匹配器does internally。)

答案 2 :(得分:1)

咄。 STDIO不是一个类 - 它是IO的一个实例,所以改变:

STDERR.any_instance.should_receive(:puts).with("=== zoo")

STDERR.should_receive(:puts).with("=== zoo")

让测试通过。