Ruby 如何扩展rspec模拟期望?

Ruby 如何扩展rspec模拟期望?,ruby,rspec,Ruby,Rspec,我想扩展和_return方法,以在参数属于异常类型时引发异常。 比如说 obj.stub(:meth).and_return(SomeException,"message") 这种构造应该在第一次调用时引发异常,在第二次调用时只返回字符串 如何用这种方法扩展rspec,是否有针对此类任务的指南 更新: 此函数的一般符号可以是: and_return_or_raise(list of arguments or/and exceptions) 怎么样 stuff = [SomeException

我想扩展
和_return
方法,以在参数属于异常类型时引发异常。 比如说

obj.stub(:meth).and_return(SomeException,"message")
这种构造应该在第一次调用时引发异常,在第二次调用时只返回字符串

如何用这种方法扩展rspec,是否有针对此类任务的指南

更新:

此函数的一般符号可以是:

and_return_or_raise(list of arguments or/and exceptions)
怎么样

stuff = [SomeException, "message"]
obj.stub(:meth).and_return do
  i = stuff.shift
  if i.respond_to?(:downcase)
    i
  else
    raise i
  end
end    
当然不是最漂亮的方式,但在你的特殊情况下应该能做到这一点。

怎么样

stuff = [SomeException, "message"]
obj.stub(:meth).and_return do
  i = stuff.shift
  if i.respond_to?(:downcase)
    i
  else
    raise i
  end
end    

当然不是最漂亮的方式,但应该在您的特定情况下完成这项工作。

因此,返回多个值的实际业务是在
RSpec::Mocks::messageexpection
类中:

def call_implementation_consecutive(*args, &block)
  @value ||= call_implementation(*args, &block)
  @value[[@actual_received_count, @value.size-1].min]
end
基本上,
call\u implementation
返回传递给
和_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
class RSpec::Mocks::messageexpection
别名\u方法:旧的\u调用\u实现\u连续,:调用\u实现\u连续
def调用\实现\连续(*参数和块)
旧的_调用_实现_连续(*args,&block)。点击do |值|
如果值为(类)&&value<异常,则提升值
结束
结束
结束

因此,返回多个值的实际业务在
RSpec::Mocks::messageexpection
类中:

def call_implementation_consecutive(*args, &block)
  @value ||= call_implementation(*args, &block)
  @value[[@actual_received_count, @value.size-1].min]
end
基本上,
call\u implementation
返回传递给
和_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
class RSpec::Mocks::messageexpection
别名\u方法:旧的\u调用\u实现\u连续,:调用\u实现\u连续
def调用\实现\连续(*参数和块)
旧的_调用_实现_连续(*args,&block)。点击do |值|
如果值为(类)&&value<异常,则提升值
结束
结束
结束

您不需要扩展任何内容——只需使用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

您不需要扩展任何内容——只需使用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

谢谢,它可以完成任务,但是让我们等待一个好的解决方案。谢谢,它可以完成任务,但是让我们等待一个好的解决方案。我指的是通用符号,所以我可以以任何顺序放置任何异常和参数。查看更新您可能可以使用自定义匹配器实现更通用的解决方案:我指的是通用表示法,因此我可以按任何顺序放置任何异常和参数。请参阅更新您可能可以使用自定义匹配器实现更通用的解决方案: