brewster
brewster

Reputation: 4492

how to yield different values for different calls with rspec

i am trying to use and_yield the same way that and_return works. i want it to yield ONE value each time its called... however it yields TWICE each time its called.

this contrived example shows the issue

class Yielder
  @@blocks = []
  def self.yielder; end
  def self.blocks= b; @@blocks << b; end
  def self.blocks; @@blocks; end
end

describe Yielder do
  it 'should yield twice' do
    allow(Yielder).to receive(:yielder).and_yield(:foo).and_yield(:bar)

    2.times do
      Yielder.yielder do |y|
        Yielder.blocks = y
      end
    end

    expect(Yielder).to have_received(:yielder).twice
    expect(Yielder.blocks).to eq [:foo, :bar]
  end
end

rspec results...

       expected: [:foo, :bar]
            got: [:foo, :bar, :foo, :bar]

am i using this incorrectly?

Upvotes: 3

Views: 641

Answers (1)

stevenharman
stevenharman

Reputation: 508

As suggested, and_yield doesn't work the same way and_return does. But if you want that kind of behavior, you could do the following:

describe Yielder do
  it 'should yield twice' do
    values = [:foo, :bar]
    allow(Yielder).to receive(:yielder) do |&block|
      block.call(values.shift)
    end

    2.times do
      Yielder.yielder do |y|
        Yielder.blocks = y
      end
    end

    expect(Yielder).to have_received(:yielder).twice
    expect(Yielder.blocks).to eq [:foo, :bar]
  end
end 

Upvotes: 4

Related Questions