Testing Rails Controllers with Nested Parameters 1

Posted by ryan
at 5:42 PM on Monday, May 22, 2006



Otherwise known as “Testing Rails Controllers with Complex Parameter Types”

A co-worker of mine and I ran into a Ruby on Rails controller testing issue recently that stumped us for quite awhile. In hindsight, it shouldn’t have.

Here is our story.

Said co-worker is new to Rails and was working through his first functional test – in this case a pretty standard login controller test. He was testing the account creation (add_user) action like this:


def test_create_account
  # Emulate account creation request
  post :add_user, { :username => 'user', :password => 'pass' }

  # Test that successful creation redirects to login
  assert_redirect_to :controller => 'login', :action => 'login'
end

Easy enough, yeah? Well yes, except this doesn’t work. I quickly figured out that it was because the controller method was looking for parameters in standard rails format as a hash of the “user” key in the param hash:


def add_user
  @user = User.new(params[:user])   #Note the "params[:user]" 
  if request.post? and @user.save
    redirect_to(:action => "login")
  end
end

Arguments were being passed in as their simple property names like username but the controller was looking for that property on the collection parameters for the user, hence the params[:user]. Okay, easy enough, we just need to pass in these nested types in our functional test.

Unfortunately, the documentation we were aware of (here and here) always use very simple examples without nested parameters.

So, after going through all of these formats modeled after what the parameters are called in the actual view:
  • :user_username = ‘user’
  • ‘user_username’ = ‘user’
  • ‘user[username]’ = ‘user’

I finally admitted defeat and took a peek at some of Typo’s functional tests to figure out what is quite intuitive in hindsight. Because you’re passing in a mock representation of the real HTTP parameters, you don’t want to use the string versions of the parameters but actually set the parameter hash directly. Duh.

So, when your controller is expecting a nested hash keyed off the :user symbol, give it one!


def test_create_account
  # Emulate account creation request
  post :add_user, { :user =>
                    {:username => 'user', :password => 'pass' }
                  }

  # Test that successful creation redirects to login
  assert_redirect_to :controller => 'login', :action => 'login'
end

Thank you open-source, and Typo specifically.

tags: ,

Comments

Leave a response

  1. LabratDecember 04, 2006 @ 08:18 AM
    Thanks for writing this down. I almost had it but this post saved me time. Too bad that by the way you figure out how to google something, you're usually damn close to figuring it out already. Cheers.
Comment