h2. Before starting

Everyone should read and understand "A Guide to testing Rails":http://manuals.rubyonrails.com/read/book/5 it is an invaluable resource for understanding how to write tests for your Rails application.

This article in not intended as a complete introduction to functional testing in Rails, read "the Guide(A Guide to testing Rails)":http://manuals.rubyonrails.com/read/book/5 for that.

h2. The problem

The objective of this howto is to write a functional test to verify that a user creation form and action actually creates a user.

Given an input form like:

(Omitting the form tag and submit button for clarity)
<pre><code>
<%= error_messages_for 'user' %>

<p><label for="User_user_name">User name</label><br />
<%= text_field 'user', 'user_name' %></p>

<p><label for="User_last_name">Last name:</label><br />
<%= text_field 'user', 'last_name' %></p>

<p><label for="User_first_name">First name:</label><br />
<%= text_field 'user', 'first_name' %></p>

<p><label for="User_email_address">E-mail address:</label><br />
<%= text_field 'user', 'email_address' %></p>

<p><label for="User_password">Password</label><br />
<%= password_field 'user', 'password' %></p>

<p><label for="User_password">Confirm password</label><br />
<%= password_field 'user', 'password_confirmation' %></p>
</code></pre>

h2. The solution

The functional test code starts with the regular suspects (this is the code that was generated when the controller was made):

<pre><code>
require File.dirname(__FILE__) + '/../test_helper'
require 'user_controller'

require 'user' # Active records to support creation test

# Re-raise errors caught by the controller.
class UserController; def rescue_action(e) raise e end; end

class UserControllerTest < Test::Unit::TestCase
  def setup
    @controller = UserController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
  end
</code></pre>

Nothing fancy there. The meat of the issue is the actual test method:

<pre><code>
  def test_create
    post(:create, {
    	 :user => {
    	 	'user_name' => 'testuser1',
    	 	'last_name' => 'User',
    	 	'first_name' => 'First',
    	 	'email_address' => 'testuser1@test.com',
    	 	'password' => 'b00bies',
    	 	'password_confirmation' => 'b00bies'
    	 } } )

    assert_response( :redirect )
    assert_redirected_to( :action => 'view' )
      
    assert User.find_by_user_name('testuser1');
  end
</code></pre>

h2. Undestanding the solution

h3. Passing @@params@ to an action

Note that the <code>user</code> hash must be explicitly constructed as part of the post operation in the test. 

In order to run the @:create@ action, we need to provide test values for @@params@ (the values that would in real life come from the form). The test methods make this an easy job: the second paramater given is assumed to be a hash of @@param@ values:

<pre>get some_action, params_values, session_values</pre>

So, for example, if we wanted to process the @:show@ method and pass in a @@param@ value of "5" for "id", we would do it like so:
<pre>
get :show, {'id' => 5}
</pre>
In the more complicated example of test @:create@, the process is the same, the only difference is that the hash has more values, and that the forms produced by @FormHelper@ pass values _within_ a hash named after the @object@ parameter.  Within rails, this nesting happens automagically; in the functional test it's the testers responsibility to build the nested hash.


h3. Asserting success

There are two key tests involved in this case. 1) Test that after running the @create@ action, the user should be redirected(in this case to the @view@ action) and 2) Test that a new @User@ record has been created that matches the given details.

h4. The redirect

The assertions involved for this part are:

<pre>
    assert_response( :redirect )
    assert_redirected_to( :action => 'view' )
</pre>

One must also be careful to realize that a redirect response is not a success response.  I stumbled over that for a few hours.

h4. User was created

Simple enough. Assert that finding the user doesn't return nil:

<pre>
    assert User.find_by_user_name('testuser1');
</pre>

_*Note:* that this test could be improved. As written this test could show false positives (where the @create@ method failed to actually make a new user, but our test incorrectly thinks it has). This could happen if there was already a user with the username "testuser1". One way around this pitfall would be to assert that no such user exists before the method is called.  Another would by including a fixture which does not include the user in question._

category:Howto
