rspec:如何在引发错误后测试ensure块

时间:2015-08-21 23:01:41

标签: ruby-on-rails ruby rspec

这是我的begin..rescue..ensure区块。我想编写一些测试用例,在引发错误后,将返回最终结果{}。 我使用的是rspec 3.3。

def external_call
  result = ExternalApi.call 
rescue => e
  # handle the error, and re-raise
  Handler.handle(e)
  raise
ensure
  result.presence || {}
end

我已经为救援部分编写了测试用例:

context 'when external api raise error' do
  it 'handles the error, and re-raise' do
    allow(ExternalApi).to receive(:call).and_raise(SomeError)
    expect(Handler).to receive(:handle).with(e)
    expect { subject.external_call }.to raise_error(SomeError)
  end
end

但我不确定如何在重新引发错误后测试确保部分。 这是我的尝试:

  it 'returns {} after error raised' do
    allow(ExternalApi).to receive(:call).and_raise(SomeError)
    result = subject.external_call
    expect(result).to eq({})
  end

在这种情况下,测试用例将在subject.external_call行中失败,因为它会在那里引发错误。我不确定在重新引发错误后如何测试这种情况。

1 个答案:

答案 0 :(得分:2)

当使用带有隐式返回的begin / rescue / ensure块时,ruby将返回要在rescue块中运行的最后一个方法作为返回值,而不是确保。如果需要返回来自ensure块的值,则必须显式返回该值,或者不将其包括在ensure中,而是移动到begin / rescue块之外。

以下是显示差异的示例。

class TestClass

  def self.method1
    raise 'an error'
  rescue
    'rescue block'
  ensure
    'ensure block'
  end

  def self.method2
    raise 'an error'
  rescue
    'rescue block'
  ensure
    return 'ensure block'
  end

  def self.method3
    begin
      raise 'an error'
    rescue
      'rescue block'
    end
    'ensure equivalent block'
  end
end

RSpec.describe TestClass do
  it do
    # does not work, method1 returns 'rescue block'
    expect(TestClass.method1).to eql 'ensure block'
  end

  it do
    # does work, as method2 explicitly returns 'ensure block'
    expect(TestClass.method2).to eql 'ensure block'
  end

  it do
    # does work, as method3 uses 'ensure equivalent block' as the inferred return
    expect(TestClass.method3).to eql 'ensure equivalent block'
  end
end