Question

In short, I want to raise an exception via a stubbed method, but only if the object that has the stubbed method has a particular state.

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

This doesn't work, because the context inside the stub block is: RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested_2.

How do I get access to the stubbed object?

using ruby 2, rspec 2.

The actual scenario is I have an app that sounds out thousands of emails in batches and I have code that catches SMTP exceptions, logs the batch, and proceeds. So I want to test sending several batches, where one of the batches in the middle throws an exception.

Was it helpful?

Solution 3

Ok, here's how you can get this behavior fairly easily without upgrading:

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

Drop that at the bottom of your spec file. You'll notice I even add a check to raise an error once RSpec is upgraded. boom!

OTHER TIPS

It looks like this is solved in the latest(currently alpha) version of 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

I believe you specify the arguments using the with method, so in your case it would be something along the lines of:

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

There's full documentation here: https://www.relishapp.com/rspec/rspec-mocks/v/2-3/docs/method-stubs

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top