Here's another interesting symptom. After tracing through the code, I've come to the understanding that the current implementation (delegated to outside rspec, I understand) of route "generation" is not testing generation at all, but rather is using backward-recognition as a proxy. Further, that recognition doesn't correspond to what the real router does recognize.
For clarity, here's the background: A resource that requires nesting for new, create; requires no nesting for edit, update, destroy, and has no index or show. > map.resources :designs, :only => [:edit, :update, :destroy] > map.resources :product, :member => { :redraw => :get } do |product| > product.resources :designs, :member => { :set_default => :put }, :except => [ :edit, :update, :destroy, :index, :show ] > end Okay: when I go to /designs/new in the browser, it borks with a RoutingError. That's the way I want it to behave, real-world. Yet, this fails: > expect { route_for(:controller => "designs", :action => "new") == > "/designs/new" }.to raise_error( ActionController::RoutingError ) There's no error raised at all here. The following does gripe, but... what it's *really* griping about (in a hidden way) is "bogus path", not about the route_for() params at all. > expect { route_for(:controller => "designs", :action => "new") == "bogus path" }.to raise_error( ActionController::RoutingError ) (so if we replace route_for([bad]) with route_for([good]) == "bogus path", then we still get the routing error. Furthermore, the first one really recognizes the route string (/designs/new), without actually verifying that there is a route in the routing table for it. So I fear that it's not actually testing what I'm asking it to test. Taking it out of the expect {} *does* make it barf, but with evidence that something is just plain confused, not that it's actually testing what we're asking it to test: [wrapping is mine] > The recognized options <{"action"=>"1", "controller"=>"designs"}> > did not match <{"action"=>"show", "id"=>"1", "controller"=>"designs"}>, > difference: <{"action"=>"show", "id"=>"1"}> At the end of the day, what I find is: * Route generation tests are not testing generation at all, but recognition only * They're only testing recognition of ideal cases * Non-existence of routes is currently not testable with rspec I hoped to just assert something on url_for() - that's the practical application, here. Does, or does not, url_for() produce a useful result with specific args? But I see from ActionController::Base how that's not super practical. I sincerely hope that my understanding is wildly mistaken. Sorry if this is a sore spot; I know that this part has been a lot of painful effort so far, far more for others than for myself. I'll end with an expression of deep and sincere appreciation for this great software. Randy ----- Original Message ---- > From: "r_j_h_box...@yahoo.com" <r_j_h_box...@yahoo.com> > To: rspec-users <rspec-users@rubyforge.org> > Sent: Tuesday, June 16, 2009 2:14:52 PM > Subject: Re: [rspec-users] Problem verifying routing error > > > David, thank you for your reply on this. I really dig the expect { }.to > raise_error() syntax!! > > To clarify: All the things you're claiming match my expectation. > Unfortunately, > my expectation does not match reality according to my tests. > > The thing is, route_for([bad stuff]) does not in and of itself raise a > routing > error. It constructs an object that hasn't yet been compared with == to > anything. > > 23 t = route_for(:controller => "designs", :action => "create") > > (rdb:1) puts t > # > > According to my tests, the routing error only occurs after route_for()'s > result > gets compared to something. So lambda { route_for(...) } does not raise > error. > > The following code passes with flying colors, either in lambda or expect > {}.to > form: > > t = route_for(:controller => "designs", :action => "create") > expect { t == "anything" }.to raise_error( ActionController::RoutingError > ) > expect { t.should == "anything" }.to raise_error( > ActionController::RoutingError ) > > Any further ideas? > > Randy > > > > > > ----- Original Message ---- > > From: David Chelimsky > > To: rspec-users > > Sent: Tuesday, June 16, 2009 1:28:18 PM > > Subject: Re: [rspec-users] Problem verifying routing error > > > > On Tue, Jun 16, 2009 at 3:07 PM, wrote: > > > > > > I finally figured this out. > > > > > > lambda { route_for(:controller => "designs", :action => "create").should > > > == > > "anything" }.should raise_error( ActionController::RoutingError ) > > > > > > The clue was that I wasn't getting a routing error until I tried to > > > compare > > route_for() with something. route_for() seems to generate an object that > > overrides ==(), and at that time it does raise the exception. Now we wrap > that > > comparison in a lambda and assert that the *comparison* should raise the > > expected routing error. > > > > > > So - great, we can actually test it. But the syntax does leave something > > > to > > > be desired. dchelimsky, can you recommend any alternatives that would be a > bit > > cleaner for testing that a route doesn't exist? > > > > > > > You don't need the .should == "anything" in there. So this is a bit cleaner: > > > > lambda { route_for(:controller => "designs", :action => "create") > > }.should raise_error( ActionController::RoutingError ) > > > > Also, since rspec-1.2.5 you can use expect/to: > > > > expect { route_for(:controller => "designs", :action => "create") > > }.to raise_error( ActionController::RoutingError ) > > > > You could always kick it old-school: > > > > e = nil > > begin > > route_for(:controller => "designs", :action => "create") > > rescue ActionController::RoutingError => e > > ensure > > e.should_not be_nil > > end > > > > And you could always wrap this in an new matcher: > > > > def be_routable > > Spec::Matchers.new :be_routable, self do |example| > > match do |params| > > e = nil > > begin > > example.route_for(params) > > rescue ActionController::RoutingError => e > > end > > !!e > > end > > end > > end > > > > {:controller => "designs", :action => "create"}.should_not be_routable > > > > In this case you need to wrap the matcher's construction in a method > > in order to provide access to the scope of the example (which is where > > route_for lives). Also, I just whipped that up off the top of my head > > - no idea if it actually works :) > > > > HTH, > > David > > > > > > > > > > > Thanks, > > > > > > Randy > > > > > > > > > > > > > > > ----- Original Message ---- > > >> From: Ben Mabey > > >> To: r_j_h_box...@yahoo.com; rspec-users > > >> Sent: Friday, May 8, 2009 10:25:03 AM > > >> Subject: Re: [rspec-users] Problem verifying routing error > > >> > > >> Randy Harmon wrote: > > >> > Hi, > > >> > > > >> > When upgrading to rspec/rspec-rails 1.2.6 gem (from 1.1.12), I'm having > > >> > a new problem verifying routes that should not exist. > > >> > > > >> > This is to support something like this in routes.rb: > > >> > > > >> > map.resources :orders do |orders| > > >> > orders.resources :items, :except => [:index,:show] > > >> > end > > >> > > > >> > I used to use lambda {}.should_raise( routing error ), but it stopped > > >> > detecting any raised error. Requesting it through the browser produces > > >> > ActionController::MethodNotAllowed (Only post requests are allowed). > > >> > But > > >> > that error wasn't detected. > > >> > > > >> > When I skip the lambda, and just ask it to verify that the route does > > >> > exist (which *should* fail), I get the same result for those :except > > >> > actions as for a made-up action name. Seems this must have something > > >> > to > > >> > do with the change in how route_for delegates back to > > >> > ActionController's > > >> > routing assertion (sez the backtrace :). > > >> > > > >> > > > >> > NoMethodError in 'ItemsController route generation should NOT map > > >> > #indewfefwex' > > >> > You have a nil object when you didn't expect it! > > >> > You might have expected an instance of Array. > > >> > The error occurred while evaluating nil.first > > >> > > > >> > > > /Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/assertions/routing_assertions.rb:134:in > > >> > `recognized_request_for' > > >> > > > >> > > > /Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/assertions/routing_assertions.rb:49:in > > >> > `assert_recognizes' > > >> > > > >> > > > /Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/assertions.rb:54:in > > >> > `clean_backtrace' > > >> > > > >> > > > /Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/assertions/routing_assertions.rb:47:in > > >> > `assert_recognizes' > > >> > ./spec/controllers/thoughts_routing_spec.rb:9: > > >> > > > >> > > > >> > I tried using bypass_rescue in my routing/items_routing_spec.rb file as > > >> > mentioned by the upgrade doc, but it wasn't valid in the "routing" spec > > >> > - worked fine when I moved the file back to spec/controllers/, though. > > >> > Seems like that's not the issue, but I'm mentioning for more > completeness. > > >> > > > >> > Any ideas what I should be doing instead, or how I can troubleshoot > > further? > > >> > > > >> > > >> > > >> Hmm.. yeah, it seems like it might have to do with how the exceptions > > >> are being handled in the newer version of rspec-rials (see > > >> > > > https://rspec.lighthouseapp.com/projects/5645/tickets/85-11818-have-mode-for-rails-error-handling). > > >> > > >> I don't use RSpec to verify my routes very often and have never used it > > >> to verify the non-existence of a route so I'm afraid I don't really have > > >> any ideas... > > >> > > >> Does anyone else have an idea to do this? > > >> > > >> -Ben > > > > > > _______________________________________________ > > > rspec-users mailing list > > > rspec-users@rubyforge.org > > > http://rubyforge.org/mailman/listinfo/rspec-users > > > > > _______________________________________________ > > rspec-users mailing list > > rspec-users@rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users