问题
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?
回答1:
You can use this:
Payment.stub_chain(:order, :where).with(:updated_at).with(:paid => true) { return_this }
回答2:
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.
回答3:
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}]
来源:https://stackoverflow.com/questions/8003445/rspec-stub-chains-with-arguments