El 08/07/2010, a las 04:45, Lalish-Menagh, Trevor escribió:

> OK, here is an idea. I was thinking about how to make routing tests
> that make sense. I agree with Wincent that the Rails verbiage for the
> routing tests is confusing, but what is NOT confusing is the new
> routing format, so why not try out this format
> (http://gist.github.com/467563):
> 
> describe 'routing another way' do
>  it { should have_resources(:days) }
>  it { should get('/days' => 'days#index') }
>  it { should match('/days' => 'days#index', :via => :get) }
>  it { should recognize('/days', :via => :get).as('days#index') }
>  it { should generate('days#index').from('/days', :via => :get) }
>  it { should recognize('/students/1/days', :via =>
> :get).as('days#index', :student_id => '1') }
> end

[snipped for brevity]

> it { should generate('days#index').from('/days', :via => :get) }

Hehe. You got it back-to-front again. "assert_generates" asserts that a _path_ 
is generated from a set of params (action, controller, additional params). Here 
you are doing the opposite, saying that certain params (action, controller) get 
generated from a path.

> The Rails test read backwards, look at this example from
> http://edgeapi.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html:
> # assert that POSTing to /items will call the create action on ItemsController
> assert_recognizes({:controller => 'items', :action => 'create'},
> {:path => 'items', :method => :post})
> 
> The comment reads like the inverse of the actual method call. I think
> that recognize(path).as(options) reads better (more like the comment
> above).

I think that's the general pattern of pretty much all Test::Unit assertions 
which compare two parameters. Where RSpec tends to say:

  actual.should == expected

Test::Unit tends to say:

  assert expected, actual

> Thoughts?

Well, this comes back to the eternal question of specing things like 
validations. Where the spec ends up being an almost identical re-statement of 
the implementation:

  validates_presence_of :foo
  it { should validate_presence_of(:foo) }

Are you testing the Rails validation code itself (which is already tested)? Are 
you testing that you remembered to include the validation itself? Do you trust 
your "validate_presence_of" matcher? Are you testing your ability to cut and 
paste? etc.

Well, same questions can arise with routing when the implementation and spec 
look like this:

  resource :days
  it { should have_resource(:days) }

So, when I see this kind of thing, I think _what_ are we trying to achieve in 
our routing specs 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 Rails routing code 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 of routing specs 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 their routing specs and _why_; and then to ask what kind of means 
RSpec should provide to best achieve those goals.

Cheers,
Wincent

_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to