Patrick Doyle wrote:

> Vahagn Hayrapetyan  wrote:

>     I'm wondering how to test POSTing something to an action from a form. I
>     am testing an action named "forgot" in my account_controller.rb. It
>     takes an email address as a parameter and does things based on whether a
>     user with that email address exists:
> 
>     def forgot
>        if request.post?
>          user = User.find_by_email(params[:user][:email])
>          if user
>            user.create_reset_code
>            flash[:notice] ="Reset code sent to #{user.email}"
>          else
>            flash[:notice] ="#{params[:user][:email]} does not exit in the
>     system."
>          end

All of that could refactor into a model method that takes an email and returns a
string:

   flash[:notice] = User.forgot_password(params[:user][:email])

The goal of refactoring is not just fatter models. Things like the 'if'
statement work better in model-land.

Further, the result becomes easier to test!

>          redirect_to index_url
>        end
>      end
> 
> 
> 
>     So I'm trying to test this like:
> 
>      def test_forgot_password
>        get 'account/forgot'
>        assert_response :success
>        assert_template 'account/forgot' #all fine so far

Putting a get and a post into the same test is bad luck. Specifically, you
should think of the secret @request and @response mock objects as consumables.
Pretend that each of 'get' and 'post' would burn them up so you can't use them
again.

(I don't know how true this mental model is; maybe you technically can reuse
them. But...)

Your get and post do not communicate anything to each other, so they should run
in two different test cases.

The one testing the get could then use assert_select, or assert_xpath, to test
for the existence of a form, and the correct fields.

>        post 'account/forgot'

Next, I thought the line should be

    post :forgot

unless you are in an integration test, which I have never been able to get much
traction from. But if you are in a functional test, then your test suite bonds
with the correct controller - AccountController - and you don't need to
redundantly declare it in get, or post, or most other helpers.

>     '[email protected]
>     <mailto:[email protected]>' #not good
>        assert_redirected_to index_url #fails
>      end
> 
>     I get:
> 
>     Expected response to be a <:redirect>, but was <500>
>     <"You have a nil object when you didn't expect it!\nYou might have
>     expected an instance of ActiveRecord::Base.\nThe error occurred while
>     evaluating nil.[]">

The top of your test suite is broken. Could you post it?

In Rails 1.x, it should have looked like this:

# Raise errors beyond the default web-based presentation
class AccountController; def rescue_action(e) raise e end; end

class AccountControllerTest < Test::Unit::TestCase

   def setup
     @controller = AccountController.new
     @request = ActionController::TestRequest.new
     @response = ActionController::TestResponse.new
   end

The point is the rescue_action line. It ensures that un-rescued errors do not 
go 
into a crash page, they cause test faults and go directly into your face when 
you run the tests.

The Rails 2 equivalent is...

   class AccountControllerTest < ActionController::TestCase

...where the new TestCase infers the controller class from the name of the 
suite, and then runs all that boilerplate code for you.

Either way, exceptions are supposed to be transmitted into your face, not into 
a 
page, and if you are using integration tests then I'd really like to hear how 
to 
get them to transmit errors correctly, too!

Aaaand here's your answer (with GMane's net-nanny foiled):

> post 'account/forgot', :user => {:email => 
> 'joeATpublic.gmane.org'}
> 
> I figured this out by the judicious use of print statements in my 
> controller printing out the values of options, options[:user], and 
> options[:user][:email].

Because you pass a subset of the complete params set into post.

One way to learn them is to write your page, run it in script/server, run your 
form, and inspect the spew from the server's console. It will include the 
params, using .inspect to write them as a raw Ruby hash.

> Hope this helps.

And I hope I didn't confuse everyone too much...

(-:

-- 
   Phlip


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to