这是我的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
行中失败,因为它会在那里引发错误。我不确定在重新引发错误后如何测试这种情况。
答案 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