Just wondering if/how arguments can be passed in rspec stub chains. To give an example, suppose I have the following action:
def index
@payments = Payment.order(:updated_at).where(:paid => true)
@bad_payments = Payment.order(:some_other_field).where(:paid => false)
end
In my controller spec, I'd like to be able to stub out both methods and return different results. If only the @payments field were in the action I'd use something like
Payment.stub_chain(:order, :where) { return_this }
But of course, that will return the same value for @bad_payments.
So - in short, how do I include the :updated_at and :paid => true as stub conditions?
You can use this:
Payment.stub_chain(:order, :where).with(:updated_at).with(:paid => true) { return_this }
With rspec > 3 use this syntax:
expect(Converter).to receive_message_chain("new.update_value").with('test').with(no_args)
instead of stub_chain.
Read more about message chains in the documenation. And here is the argument matchers documentation.
You can use nested stub block. The block can accept arguments, and the return value is used as function return value.
I use tap because stub does not returns the callee. The mock created by double is returned as the result of method order, which where method is stub again.
Payment.stub(:order) { |order|
double('ordered_payments').tap { |proxy|
proxy.stub(:where) { |where|
[order, where]
}
}
}
Payment.order(:updated_at).where(:paid => true)
# => returns [:updated_at, {:paid => true}]
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