zobie's blog I create software, I like music, and I'm mildly(?) OCD.

20Nov/08

Testing Routes in Rails

Routes in rails are really cool but they can be confusing to newbies and, as they become more complex, it can be difficult to make sure that all of your paths are still working like you expect. My intention here is not to provide a primer on routes but rather to show how easy it is to test and verify routes.

As you define new routes it is important to write tests to validate url formats. You need tests to verify that urls are mapped to the right controller and action:

assert_generates("/directory/stations",
                 :controller => "dashboard",
                 :action => "directory_stations")

And you need tests to verify that controller/action combinations can be correctly mapped back to a url:

assert_recognizes({ :controller => "dashboard",
                    :action => "directory_stations" },
                  "/directory/stations")

The console is your friend when you are trying to test or debug a tricky mapping. Launch the console and, to save some typing, assign a local variable:

$ script/console
>> r = ActionController::Routing::Routes

If you want to see currently defined routes:

>> puts r.routes
ANY /:controller/:action/:id/ {}
ANY /:controller/:action/:id.:format/ {}
=> nil

The first part of the output tells you what HTTP verb the routing applies to, ANY in this case. Other possible values are GET, POST, HEAD, etc. The next element in the output is the pattern that matches the route. The empty braces show that we don't have any of the optional parameters defined that might modify the behavior of the route.

To verify that urls are mapped to the right controller and action use recognize_path:

>> r.recognize_path "/station/index/42.html"
=> {:controller=>"station", :action=>"index", :format=>"html", :id=>"42"}
>> r.recognize_path "/station/index/42"
=> {:controller=>"station", :action=>"index", :id=>"42"}
>> r.recognize_path "/station/index"
=> {:controller=>"station", :action=>"index"}
>> r.recognize_path "/station"
=> {:controller=>"station", :action=>"index"}

To verify that controller/action/id/etc. combinations correctly map back to a url:

>> r.generate :controller => :station
/station
=> nil
>> r.generate :controller => :station, :action=> :index
/station
=> nil
>> r.generate :controller => :station, :action=> :index, :id=>42
/station/index/42
=> nil
>> r.generate :controller => :station, :action=> :index, :id=>42, :param => "xyzzy"
/station/index/42?param=xyzzy
=> nil