如何扩展rspec模拟期望?

时间:2013-01-08 14:29:46

标签: ruby rspec

如果参数是一种异常,我想扩展and_return方法以引发异常。 例如

obj.stub(:meth).and_return(SomeException,"message")

这种结构应该在第一次调用时引发异常,并在第二次调用时返回该字符串。

如何通过这种方法扩展rspec,是否有这种任务的指导方针?

更新:

此功能的一般表示法可能是:

and_return_or_raise(list of arguments or/and exceptions)

3 个答案:

答案 0 :(得分:1)

怎么样

stuff = [SomeException, "message"]
obj.stub(:meth).and_return do
  i = stuff.shift
  if i.respond_to?(:downcase)
    i
  else
    raise i
  end
end    
肯定不是最漂亮的方式,但应该在你的特定情况下做好工作。

答案 1 :(得分:1)

因此,返回多个值的实际业务是RSpec::Mocks::MessageExpectation类中的this method

def call_implementation_consecutive(*args, &block)
  @value ||= call_implementation(*args, &block)
  @value[[@actual_received_count, @value.size-1].min]
end

基本上,call_implementation返回您传递给and_return的预期返回值列表,此方法选出与当前调用相对应的值(如果我们更多地调用该方法,则返回最后一个值)时间比列表中的值少。)

所以,为了做你想做的事,你可以按照以下方式修补这个方法:

class RSpec::Mocks::MessageExpectation
  alias_method :old_call_implementation_consecutive, :call_implementation_consecutive

  def call_implementation_consecutive(*args, &block)
    old_call_implementation_consecutive(*args, &block).tap do |value|
      raise value if value.is_a?(Class) && value < Exception
    end
  end
end

答案 2 :(得分:1)

您不需要扩展任何内容 - 只需使用RSpec的内置错误匹配器并接收计数:

class Foobar
  def foo
    bar
  end
end

it "raises the first time, then returns a string" do
  obj = Foobar.new
  obj.should_receive(:bar).once.and_raise(StandardError)
  obj.should_receive(:bar).once.and_return("message")
  expect { obj.foo }.to raise_error(StandardError)
  obj.foo.should == "message"
end