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? 
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
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With