Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSpec: How to Stub Only One of Multiple Calls to Same Method

I'm having trouble figuring out how to stub only one of two calls to a method. Here's an example:

class Example
  def self.foo
    { a: YAML.load_file('a.txt'),   # don't stub - let it load
      b: YAML.load_file('b.txt') }  # stub this one
  end
end

RSpec.describe Example do
  describe '.foo' do
    before do
      allow(YAML).to receive(:load_file).with('b.txt').and_return('b_data')
    end

    it 'returns correct hash' do
      expect(described_class.foo).to eq(a: 'a_data', b: 'b_data')
    end
  end
end

The test fails because I have stubbed a call to YAML.load_file with the args for the second call ('b.txt'), not the first one it encounters('a.txt'). I thought argument matching would address this but it does not.

Failures:

  1) Example.foo returns correct hash
     Failure/Error:
       { a: YAML.load_file('a.txt'),
         b: YAML.load_file('b.txt') }

       Psych received :load_file with unexpected arguments
         expected: ("b.txt")
              got: ("a.txt")
        Please stub a default value first if message might be received with other args as well.  

Is there a way I can allow the first call to YAML.load_file to go through but only stub the second call? How would I do this?

like image 595
doremi Avatar asked Dec 18 '22 19:12

doremi


1 Answers

There is a and_call_original option (see rspec docs).

Applied to your example, this should do what you are looking for:

before do
  allow(YAML).to receive(:load_file).and_call_original
  allow(YAML).to receive(:load_file).with('b.txt').and_return('b_data')
end
like image 146
periswon Avatar answered Dec 30 '22 07:12

periswon