Rails 3, RSpec 2.5: Using should_receive or stub_chain with named scopes
Asked Answered
B

2

11

I use Rails 3.0.4 and RSpec 2.5. In my controllers I use named scopes heavily, for example

   @collection = GuestbookEntry.nonreplies.bydate.inclusive.paginate(
       :page => params[:page], :conditions => { ... })

In my tests, I want to be able to mock the result of such a query, not the wording. I do not think it makes sense to do something like

   GuestbookEntry.stub_chain(:nonreplies, :bydate, ...).and_return(...)

because this test will fail the moment I decide to reorder the named scopes.

With Rails 2.3 and RSpec 1.x, this worked fine: I could write

   GuestbookEntry.should_receive(:find).with(:all, :conditions => { ... })

and the above call would be caught and correctly handled. However, with Rails 3, for some reason this does not work any more.

Why? How do I set expectations or stubs on the result of nested scopes? Since everything in Rails 3's ActiveModel is a named scope (thanks to ARel), this must be possible somehow, or tests would indeed be very brittle.

Thanks!

Update: See also issue report on GitHub.

Borgeson answered 9/3, 2011 at 20:8 Comment(0)
G
1

This problem has bugged me for a while too!

I believe the reason the behaviour is different from Rails 2 is because the query is no longer being performed during the variable assignment in the controller. Instead, it's lazy-loaded as required.

I agree with Mark Wilden that it's better to wrap all of these scopes in a larger scope and spec that in your model. This scope clearly has a specific function, so just as one would spec the behaviour of a method which calls several other methods, you would spec the behaviour of a scope that joins several other scopes.

Greenshank answered 21/5, 2011 at 23:24 Comment(0)
V
0

I would wrap such a complicated query in its own scope, and stub that.

V1 answered 23/4, 2011 at 6:14 Comment(2)
Then how do I write specs which verify that the single scope does what it is supposed to do? My idea was to write multiple simple scopes which are obvious so that almost nothing inside them can "go wrong", and then combine them, because it is so hard to spec scopes (without resorting to populating and querying a real database with real data).Borgeson
I think you have to spec each "full scope" else you won't know that you did combine them properly. Even if you spec that the right combination was done, you need an overall spec to show that that combination itself was the right way to solve the problem. But if you put the complicated scope in its own scope, you at least don't have to worry about the order of the "wording" since it is only done in once place. I don't think you can get away from populating a database. Personally, I find it easier (and "safer") to use factories to set up real data than to mock out model methods.V1

© 2022 - 2024 — McMap. All rights reserved.