Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

testing methods wrapped in blocks with RSpec

In my simplified example of what I'm actually doing, let's say I have 2 calls to the database:

Repo.add( something_stringy )
Repo.remove( something_floaty )

and I want to use mocks for the database calls, as the real calls will be tested elsewhere:

let(:repo){
  repo = double("Repo")
  repo.should_receive(:add).with(instance_of(String))
  repo.should_receive(:remove).with(instance_of(Float))
  repo
}

before { FakeKlass.const_set :Repo, repo }

that's all fine and dandy, but now if I wrap the calls in a transaction I'm a bit stumped:

Repo.transaction do
  # ... some error checking in here somewhere...
  Repo.add( something_stringy )
  Repo.remove( something_floaty )
end

because if I write a mock that receives transaction it will receive the call, but everything in the block won't get called, and I get:

expected: 1 time received: 0 times

for all of the other mocks. Would anyone be able to show me how I should be writing my spec to deal with this? I've tried reading the relevant page in the RSpec book on around(:each) but that was about as clear as mud to me.

Any help is much appreciated.

like image 446
ian Avatar asked May 11 '11 02:05

ian


1 Answers

You can use #and_yield to yield from an expectation chain:

repo.should_receive( :transaction ).and_yield

You also don't need to set up a double to stub out methods on your Repo class. For example, your setup could be written:

before( :each ) do
    Repo.should_receive( :transaction ).and_yield
    Repo.should_receive( :add ).with( instance_of(String) )
    Repo.should_receive( :remove ).with( instance_of(Float) )
end

You might also consider using stub instead of should_receive, as it doesn't set up expectations:

before( :each ) do
    Repo.stub( :transaction ).and_yield
    Repo.stub( :add )
    Repo.stub( :remove )
end

In general, you should only use should_receive when you want to test the interaction between two objects. My own personal rule of thumb is that if it appears in a before, use stub; if it's in an example, especially with a specific value, use should_receive.

like image 151
Michael Granger Avatar answered Oct 03 '22 22:10

Michael Granger