[rspec-users] Possible improvements to routing spec API

David Chelimsky dchelimsky at gmail.com
Wed Sep 29 07:56:30 EDT 2010

On Aug 17, 2010, at 12:46 PM, Michael Kintzer wrote:

> On Jul 7, 11:25 pm, Wincent Colaiuta <w... at wincent.com> wrote:
>> So, when I see this kind of thing, I think _what_ are we trying to achieve in ourroutingspecs and _why_? At least for me, the answers are:
>>   1. Confirm: To confirm that the routes I've defined actually do what I think they do
>>   2. Describe: To serve as a complete, explicit, readable specification of the behavior I expect from my routes
>> And finally:
>>   3. That the Railsroutingcode actually works as advertised
>> This last one is a bit dubious, but the truth is the Rails 3 router is a complete re-write and bugs in it and incompatibilities with the old router are being found and squished constantly. An exhaustive set ofroutingspecs can definitely help to uncover undiscovered edge cases.
>> So, bearing in mind those goals, what I actually need from RSpec in order to achieve them is:
>>   - most importantly, a way of asserting that a user action (eg. HTTP verb + path + params) gets routed to a given controller + action with certain additional parameters (ie. a wrapper for assert_recognizes)
>>   - less importantly, a way of asserting that a set of params (action, controller, additional params) generates a particular path (ie. a wrapper for assert_generates); this is less important for me because in practice close to all (98%) of my URL generation is done with named URL helpers, and I can test those explicitly if I want
>>   - as syntactic sugar, a way of combining the above two assertions into one for those cases where the mapping is perfectly bidirectional (ie. a wrapper for assert_routing).
>> With these tools I can achieve pretty much everything I need: not only test that user actions end up hitting the right spots in my application, but also specify clearly and explicitly what I expect those mappings to be.
>> So for me, anything else doesn't really help me achieve my goals. The "have_resource(s)" matcher, for instance, doesn't help me and in fact actually undermines my goal of providing a complete and explicit specification of how my routes work.
>> The "recognize" and "generate" matchers you suggest obviously are "on target" to help me fulfill my goals. Of these, the "recognize" one is the most important one though.
>> Of the "match" and "get" matchers you suggest, seeing as they both wrap the same thing (assert_routing), one of them would have to go. I'd probably ditch "match" because it is just a repetition of the router DSL method of the same name, and my goal here isn't just to repeat that DSL in my specs.
>> In fact, if you look at my most important goal -- asserting that a user action (HTTP verb, path, params) hits a specific end point (controller + action + additional params) -- you'll understand why, in my proposal, all of my specifications start with "get"/"post" etc followed by path, params and then controller/action. It's not just for resonance with other parts of RSpec like where we use "get" etc in controller specs.
>> But if the goal is just to wrap the 3 Rails assertions as faithfully as possible, then you wind up with a different proposal. What David has posted is probably the closest to this goal.
>> And if the goal is make the specs map as closely as possible onto the language of config/routes.rb, then you wind up with a different proposal still... (ie. the one you just made).
>> So, I guess what I'm saying here is I'd like to hear _what_ people are wanting to achieve in theirroutingspecs and _why_; and then to ask what kind of means RSpec should provide to best achieve those goals.
>> Cheers,
>> Wincent

> Lots of good proposals here.  I would at least like to chime in that I
> agree with the goals as set out by Wincent below, and from a
> readability standpoint have preferred the API as suggested by
> Trevor.
> -Michael

Time to resurrect this discussion.

Thinking about Wincent's very thoughtful synopsis has lead me to a slightly different line of thinking here.

We've always seen route recognition and route generation as opposite sides of the same coin, but I think that's due to how they are presented to us by the Rails testing facilities. The more I think of it, route generation is not really the concern of the router at all. It's a responsibility of controllers (and views, by proxy) to generate a recognizable route from a set of params.

What this leads me to is that I'd like to simplify all of this and make route_to only care about the routing side of this equation (i.e. have it delegate to assert_recognizes, rather than assert_routing).

The implication of this would be that we'd theoretically lose coverage that routes are generated correctly, but I don't think that actually matters. We still need to assemble the right parameters in our controllers/views to get the routes we want, so those should be specified in relation to the controller or view. i.e. in a view spec:

  rendered.should have_css("a", :href => projects_path)

The fact that the controller can generate that link from {:controller => "projects", :action => "index"} is a matter of Rails working as advertised. Plus, if we wrote that link in a view and it generated an unrecognizable route, the error message we'd get is that no route matches, not that the route could not be generated.

To sum up: I'd like to have route_to delegate to assert_recognizes, and leave it at that.

That said, I'd be perfectly willing to add some of the sugar that has been proposed in this thread, so we can say:

  get("/").should route_to("projects#index")

I agree that this is more terse, yet very expressive in the context of other facilities we're dealing with.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20100929/8470ef9a/attachment.html>

More information about the rspec-users mailing list