Rspec应该存在并中止

时间:2014-01-21 21:39:53

标签: ruby rspec rspec2

我有以下代码:

class Init
  def initialize(global_options, options, args)
    abort "Key file must be given!" if (key_file = args.first).nil?

    begin
      @secret = File.read(key_file)
    rescue
      abort "Cannot read key file #{key_file}"
    end

    stdout, stderr, status = Open3.capture3("git status  -uno --porcelain")
    #...

并遵循以下规范:

describe Rgc::Init do
  context :initialize do
    it 'should abort when no key file given' do
      Rgc::Init.any_instance.should_receive(:abort)
        .with("Key file must be given!")

      Rgc::Init.new({}, {}, [])
    end
  end
end

我得到以下输出:

Failure/Error: Rgc::Init.new({}, {}, [])
#<Rgc::Init:0x0000000157f728> received :abort with unexpected arguments
expected: ("Key file must be given!")
got: ("Cannot read key file ")

should_receive方法以某种方式阻止中止占据一席之地。如何修复规范以检查应用程序是否已中止并具有特定消息?

1 个答案:

答案 0 :(得分:4)

你的两个期望需要被视为单独的事物。首先,正如您所注意到的那样,abort现在已经存根,因此实际上并没有中止代码的执行 - 现在它实际上就像puts语句一样。因此,中止被调用两次:一次是您的预期消息,然后是begin块内。如果你在预期结束时添加{ abort },它实际上会中止,但这也会中止你的测试套件。

你应该做的是使用lambda并确保调用abort

lambda { Rgc::Init.new({}, {}, []) }.should raise_error SystemExit

abort将您提供的消息打印到stderr。要捕获它,您可以添加一个帮助程序来暂时用StringIO对象替换stderr,然后您可以检查以下内容:

def capture_stderr(&block)
  original_stderr = $stderr
  $stderr = fake = StringIO.new
  begin
    yield
  ensure
    $stderr = original_stderr
  end
  fake.string
end

it 'should abort when no key file given' do
  stderr = capture_stderr do
    lambda { Rgc::Init.new({}, {}, []) }.should raise_error SystemExit
  end
  stderr.should == "Key file must be given!\n"
end

(感谢https://stackoverflow.com/a/11349621/424300替换stderr)