Using url_for in Ruby on Rails tests

Posted by Ben on May 04, 2007

On a recent Ruby on Rails project, we ran into a situation where we needed to use the ActionController::Base url_for method in our tests. My first attempt was to simply write the test as follows:

def test_next__should_show_step3
  @request.env["HTTP_REFERER"] = @controller.url_for(
    :controller => 'wizard',
    :action => 'step',
    :step_number => "1",
    :id => 1)
 
  post :next, :id => 1
  assert_not_nil
  assigns(:virtual_tour)
  assert_response :redirect
  assert_redirected_to :action => 'step', :step_number => "3", :id => assigns(:virtual_tour).id
end

When I ran the test it resulted in the following error:

test_next__should_show_step3(VirtualTourWizardControllerTest):
NoMethodError: You have a nil object when you didn't expect it! The error occured while evaluating nil.rewrite
/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/base.rb:488:in `url_for'
./test/functional/virtual_tour_wizard_controller_test.rb:91:in `set_referer_step'
./test/functional/virtual_tour_wizard_controller_test.rb:64:in `test_next__should_update_virtual_tour'

When we looked at the rails code, we saw that an instance variable @url was not initialized yet in our tests. This was causing the nil error seen above. We found a post that wrote about a work around by initializing this variable by calling get :index or some other action that doesn’t cause a side effect. This seems like a bit of a hack so we dug a little further.

After a little digging in the rails source code, we found the class that does the actual URL rewriting. The class is called ActionController::UrlRewriter which url_for delegates to to do the actual URL rewriting. So we created a little helper method in test_helper.rb to wrap ActionController::UrlRewriter in a nice helper method called url_for. The following is the method we created in test_helper.rb

def url_for(options)
  url = ActionController::UrlRewriter.new(@request, nil)
  url.rewrite(options)
end

We can know rewrite our test to look like this.

def test_next__should_show_step3
  @request.env["HTTP_REFERER"] = url_for(
    :controller => 'wizard',
    :action => 'step',
    :step_number => "1",
    :id => 1)
 
  post :next, :id => 1
  assert_not_nil
  assigns(:virtual_tour)
  assert_response :redirect
  assert_redirected_to :action => 'step', :step_number => "3", :id => assigns(:virtual_tour).id
end

We ended up doing a little more refactoring after this since we set the referer like this in many of our other tests.

Trackbacks

Use this link to trackback from your own site.

WordPress database error: [Table './jotthought_blog/wp_comments' is marked as crashed and should be repaired]
SELECT * FROM wp_comments WHERE comment_post_ID = '24' AND comment_approved = '1' ORDER BY comment_date

Comments

Leave a response

Comments