Testing Custom and Named Routes

Problem

You want to test whether your customized routing rules are directing incoming URLs to actions correctly, and that options passed to url_for are translated into the correct URLs. Basically, you want to test what you've defined in config/routes.rb, including custom rules and named routes.

Solution

Assume you have a blog application with the following custom routing:

config/routes.rb:

ActionController::Routing::Routes.draw do |map|
 map.home '', :controller => 'blog', :action => 'index'
 map.connect ':action/:controller/:id', :controller => 'blog', 
 :action => 'view'
end

The Blog controller defines view and index methods. The view method returns an instance variable containing a Post if an :id exists in the params hash; otherwise the request is redirected to the named route, home_url.

app/controllers/blog_controller.rb:

class BlogController < ApplicationController
 def index
 end
 def view
 if (params[:id])
 @post = Post.find(params[:id])
 else 
 redirect_to home_url
 end
 end end

To test the generation and interpretation of URLs and the named route defined in routes.rb, add the following test methods to blog_controller_test.rb:

test/functional/blog_controller_test.rb:

require File.dirname(__FILE__) + '/../test_helper'
require 'blog_controller'
class BlogController; def rescue_action(e) raise e end; end class BlogControllerTest < Test::Unit::TestCase
 def setup
 @controller = BlogController.new
 @request = ActionController::TestRequest.new
 @response = ActionController::TestResponse.new
 end
 def test_url_generation
 options = {:controller => "blog", :action => "view", :id => "1"}
 assert_generates "view/blog/1", options 
 end
 def test_url_recognition
 options = {:controller => "blog", :action => "view", :id => "2"} 
 assert_recognizes options, "view/blog/2" 
 end
 def test_url_routing
 options = {:controller => "blog", :action => "view", :id => "4"} 
 assert_routing "view/blog/4", options 
 end
 def test_named_routes
 get :view
 assert_redirected_to home_url
 assert_redirected_to :controller => 'blog'
 end
end

Run these functional tests with:

$ rake test:functionals

Discussion

Being able to test customized routing rules that may contain complex pattern matching is easy with the routing-related assertions that Rails provides.

The test_url_generation test method uses assert_generates, which asserts that the options hash passed as the second argument can generate the path string in the first argument position. The next test, test_url_recognition, exercises the routing rules in the other direction with assert_recognizes, which asserts that the routing of the path in the second argument position was handled and correctly translated into an options hash matching the one passed in the first argument position.

assert_routing in test_url_routing test tests the recognition and generation of URLs in one call. Internally, assert_routing is just a wrapper around the assert_generates and assert_recognizes assertions.

Finally, the named route (map.home) is tested in the test_named_routes method by issuing a get request to the view action of the Blog Controller. Since no id is passed, request should be redirected to the named route. The call to assert_redirected_to confirms that this redirection happened as expected.

See Also