Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSpec: Matching arguments for receive_message_chain

I'm trying to stub:

Thing.where(uuid: options['uuid']).first

Via:

allow(Thing).to receive_message_chain(:where, :first)
  .with(uuid: thing_double.uuid)
  .and_return(nil)

But this is returning:

 #<Double (anonymous)> received :first with unexpected arguments
         expected: ({:uuid=>123})
              got: (no args)

Is there a different way I should be validating arguments for message chains?

like image 874
doremi Avatar asked Jul 12 '16 16:07

doremi


2 Answers

It's sometimes error prone (I'll intermittently get an error saying "wrong number of arguments (0 for 1+)"; although this seems to only happen when performing multiple receive_message_chains in a single test), but you can also opt for chaining your "with" methods thus:

expect(User).to receive_message_chain(:where, :order).with(active: true).with('name ASC')
like image 141
Nathan Crause Avatar answered Sep 22 '22 00:09

Nathan Crause


It doesn't appear that you can use with in combination with receive_message_chain when the arguments pertain anything other than the final method. Thus the message:

#<Double (anonymous)> received :first with unexpected arguments

This makes sense -- how can RSpec know which method in the chain should receive the arguments?

To verify the argument expectation, don't stub the chain, just stub where

allow(Thing).to receive(:where).with(uuid: 1).and_return([])
expect(Thing.where(uuid: 1).first).to eq nil

Or omit the arguments:

 allow(Thing).to receive_message_chain(:where, :first).and_return(nil)
 expect(Thing.where(uuid: 1).first).to eq nil

receive_message_chain is not recommended IMO. From the docs:

you should consider any use of receive_message_chain a code smell

like image 38
zetetic Avatar answered Sep 21 '22 00:09

zetetic