如何存根ruby方法并根据对象状态有条件地引发异常

时间:2014-01-24 00:40:54

标签: ruby rspec tdd rspec2

简而言之,我想通过存根方法引发异常,但前提是具有存根方法的对象具有特定状态。

Mail::Message.any_instance.stub(:deliver) do
  if to == "notarealemailaddress!@#!@#"
    raise Exception, "SMTP Error"
  else
    return true
  end
end

这不起作用,因为存根块内的上下文是:RSpec :: Core :: ExampleGroup :: Nested_1 :: Nested_2 :: Nested_2。

如何访问存根对象?

使用ruby 2,rspec 2。

实际情况是我有一个应用程序,批量发出数千封电子邮件,我有代码捕获SMTP异常,记录批次,并继续。所以我想测试发送几个批次,其中一个批次在中间引发异常。

3 个答案:

答案 0 :(得分:1)

看起来这是在最新的(目前为alpha版)的Rspec v3:

中解决的

https://github.com/rspec/rspec-mocks/commit/ebd1cdae3eed620bd9d9ab08282581ebc2248535#diff-060466b2a68739ac2a2798a9b2e78643

it "passes the instance as the first arg of the implementation block" do
   instance = klass.new

   expect { |b|
     klass.any_instance.should_receive(:bees).with(:sup, &b)
     instance.bees(:sup)
   }.to yield_with_args(instance, :sup)
end

答案 1 :(得分:0)

我相信您使用with方法指定参数,因此在您的情况下,它将是以下内容:

Mail::Message.any_instance.stub(:deliver).with(to: "notarealemailaddress!@#!@#") do
    raise Exception, "SMTP Error"
end

这里有完整的文档: https://www.relishapp.com/rspec/rspec-mocks/v/2-3/docs/method-stubs

答案 2 :(得分:0)

好的,以下是如何在不升级的情况下轻松获得此行为的方法:

class Rspec::Mocks::MessageExpectation
  # pulling in behavior from rspec v3 that I really really really need, ok?
  # when upgrading to v3, delete me!
  def invoke_with_orig_object(parent_stub, *args, &block)
    raise "Delete me.  I was just stubbed to pull in behavior from RSpec v3 before it was production ready to fix a bug!  But now I see you are using Rspec v3. See this commit: https://github.com/rspec/rspec-mocks/commit/ebd1cdae3eed620bd9d9ab08282581ebc2248535#diff-060466b2a68739ac2a2798a9b2e78643" if RSpec::Version::STRING > "2.99.0.pre"
    args.unshift(@method_double.object)
    invoke_without_orig_object(parent_stub, *args, &block)
  end
  alias_method_chain :invoke, :orig_object
end

将其放在spec文件的底部。您会注意到,我甚至会在RSpec升级后添加一个检查来引发错误。吊杆!