Best practices for testing Routes?

I'm wondering if there are any accepted practices for testing routes in rails. For instance, if I added a route like:

map.root :controller => 'welcome'

And I wanted to add an assertion like:

assert_routing '', :controller => 'welcome', :action => 'index'

Where should tests like this be placed? It seems like they could go in a routes.rb testing class, but would that go in the functional tests folder or in the integration folder? Or a test could be added to the welcome controller's tests, since it's the one that should handle the request.

I've been looking around online, and looking through some open source rails apps, but I haven't found an answer yet. Is there a right place for this?

Maybe I'm being overly defensive in my testing.

I tend to take the perspective that there should be a test for anything that I expect the application to do. That way the tests can act as a specification for what is expected of the app, and also they guard against me doing something stupid in the future, like adding a higher priority route that preempts the route I'm testing.

I was trying to provide the simplest example possible to avoid forcing people to read too much, but I'm afraid my example might have been too simple. I don't intend to test that "map.root" works, instead I want to test that my application routes requests the way I want it to.

Here is a more in depth example of the sort of tests I'm thinking of. Say I wanted to create a blog like the one described in example 2 of the Rails Introduction to Routes page at Peak Obsession.

If I approached this using test driven methodology I would write a test and then add a route to fulfill that test. So, when I added my posts/show/10 route there would have been a test proving that it worked. Later when I added the new route from the example:

map.connect ':year/:month/:day', :controller => 'blog', :action => 'by_date'

I would immediately notice that my posts/show/10 test failed. Then it wouldn't take long to realize that the new route was too vague, and it was matching the posts route when it shouldn't. So, I could get to the better route from the example with less effort:

map.connect 'date/:year/:month/:day', :controller => 'blog', :action => 'by_date',               :month => nil, :day => nil,               :requirements => {:year => /\d{4}/, :day => / \d{1,2}/, :month => /\d{1,2}/}

Without tests to validate my routes I might not have noticed this mistake as quickly, and once I did notice it might take me longer to find the problem if I had made other changes between adding the problem route and noticing the problem.

I realize not everyone uses TDD, but I'm sure some Rails developers do. I'm wondering if any test first Rails people out there have any advice on where to stick tests of this nature.

ryan_s, I tend to put these tests in the same file that tests the controller to which the route is connected. For the example in this message, that'd be in test/functional/blog_controller_test.rb. But know that there are two forms that your testing needs to take.

For a GET route, it's as simple as (I always put a test that the controller name is right, too):

   def test__controller_naming      assert_equal('similarity', @controller.controller_name,                   "None of the routing tests will work if controller_name is not 'similarity'")    end

   # for a non-standard default action    def test__route_similarity_categories      assert_routing '/similarity', { :controller => 'similarity', :action => 'categories' }    end

   # for a nested-ish resource    def test__route_similarity_candidates      assert_routing('/similarity/1/group/2',                     { :controller => 'similarity', :action => 'list',                       :id => '1', :trait_group => '2' })    end

However, if you want to test that the specific kind of request is used, you need to use the two separate methods that assert_routing uses internally because there's no way to pass all the needed options through.

   # Need to split these out in order to require that POST is used.    def test__route_similarity_make_similar      assert_recognizes({ :controller => 'similarity', :action => 'make_similar',                          :id => '1', :trait_group => '2', :leader => '3', :follower => '4' },                        { :path => '/similarity/1/group/2/3/4', :method => :post })

     assert_generates('/similarity/1/group/2/3/4',                       { :controller => 'similarity', :action => 'make_similar',                         :id => '1', :trait_group => '2', :leader => '3', :follower => '4' })    end

This route happens to be for an AJAX'd action so less fluff in the URL wasn't a concern.


Rob Biedenharn

Thanks Rob, this is just the sort of information I was looking for.


The way I think about this is that I'm testing that what I put in my config/routes.rb file does what I think it should.

For those using RSpec, the latest version makes two specs for a controller if you use the "script/generate rspec_scaffold foo" command

specs    controllers        foos_controller_spec.rb        foos_routing_spec.rb

The foos_controller_spec.rb corresponds roughly to the test case for the controller in the test/integration directory and contains specifications of the behavior of the controller.

The foos_routing_spec.rb contains specs for routes pertaining to the FoosController.

I was quite skeptical about Rspec when I first learned of it a year ago, but it's winning me over.

That's interesting Rick. I've been meaning to look into RSpec for a while now, but this gave me the impetus to actually do it. It looks to me like a nice way of providing more verbose tests. I think I'll give it a try and see how I like it. Thanks for the tip.