# Testing a POST request with correct param

**URL:** <https://www.ruby-forum.com/t/testing-a-post-request-with-correct-param/156723>\
**Category:** Rails\
**Created:** [January 1, 2009, 11:25pm UTC](https://www.ruby-forum.com/t/testing-a-post-request-with-correct-param/156723 "2009-01-01T23:25:38Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![vahagn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/cc9497/32.png) [@vahagn](https://www.ruby-forum.com/u/vahagn)\
**Post date:** [January 1, 2009, 11:25pm UTC](https://www.ruby-forum.com/t/testing-a-post-request-with-correct-param/156723/1 "2009-01-01T23:25:38Z")

</div>

Hi,-

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  
redirect\_to index\_url  
end  
end

The HTML looks like this:

Enter email address:

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  
post ‘account/forgot’, ‘removed\_email\_address@domain.invalid’ #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.[]”\>

I’m not sure if the request parameter is wrongly formed? The app must  
redirect to the index url regardless of the validity of the email  
address. So the error must lie elsewhere I guess!

Thanks and oh, a Happy New (Rails) Year 🙂

---

<div class="post-metadata">

**Author:** ![vahagn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/cc9497/32.png) [@vahagn](https://www.ruby-forum.com/u/vahagn)\
**Post date:** [January 2, 2009, 3:32am UTC](https://www.ruby-forum.com/t/testing-a-post-request-with-correct-param/156723/2 "2009-01-02T03:32:55Z")

</div>

On Thu, Jan 1, 2009 at 5:25 PM, Vahagn H. \<  
removed\_email\_address@domain.invalid\> wrote:

> ```
> user = User.find_by_email(params[:user][:email])
> 
> ```
> 
> 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.[]”\>

It’s funny you should ask this, as I spent this morning trying to figure  
this out myself for my project. Your post in #test\_forgot\_password  
needs to  
look something like:

post ‘account/forgot’, :user =\> {:email =\> ‘removed\_email\_address@domain.invalid’}

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].

Hope this helps.

–wpd

---

<div class="post-metadata">

**Author:** ![vahagn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/cc9497/32.png) [@vahagn](https://www.ruby-forum.com/u/vahagn)\
**Post date:** [January 2, 2009, 5:22am UTC](https://www.ruby-forum.com/t/testing-a-post-request-with-correct-param/156723/3 "2009-01-02T05:22:51Z")

</div>

Patrick D. wrote:

> Vahagn H. wrote:

> ```
> 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!

> ```
> 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.

> ```
> 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](http://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

---

<div class="post-metadata">

**Author:** ![vahagn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/cc9497/32.png) [@vahagn](https://www.ruby-forum.com/u/vahagn)\
**Post date:** [January 2, 2009, 9:02pm UTC](https://www.ruby-forum.com/t/testing-a-post-request-with-correct-param/156723/4 "2009-01-02T21:02:09Z")

</div>

On Fri, Jan 2, 2009 at 2:53 PM, Vahagn H. \<  
removed\_email\_address@domain.invalid\> wrote:

> puts "OPTIONS: " + options[:user] #method undefined!  
> etc etc  
> .

Yup. I’m not sure why you would get a #method undefined! error. I got  
all  
sorts “you have tried to call nil.something” errors, which pointed in  
the  
direction of realizing that options[:foo][:bar] was not set.

I’m glad I could help. I have received so much help from the folks on  
this  
list that it’s a pleasure to be able to give some back.

–wpd

---

<div class="post-metadata">

**Author:** ![vahagn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/cc9497/32.png) [@vahagn](https://www.ruby-forum.com/u/vahagn)\
**Post date:** [January 2, 2009, 9:46pm UTC](https://www.ruby-forum.com/t/testing-a-post-request-with-correct-param/156723/5 "2009-01-02T21:46:53Z")

</div>

… and I’m looking forward to the day I’m able to give back, as well.  
/ V.

Patrick D. wrote:

> On Fri, Jan 2, 2009 at 2:53 PM, Vahagn H. \<  
> removed\_email\_address@domain.invalid\> wrote:
> 
> > puts "OPTIONS: " + options[:user] #method undefined!  
> > etc etc  
> > .
> 
> Yup. I’m not sure why you would get a #method undefined! error. I got  
> all  
> sorts “you have tried to call nil.something” errors, which pointed in  
> the  
> direction of realizing that options[:foo][:bar] was not set.
> 
> I’m glad I could help. I have received so much help from the folks on  
> this  
> list that it’s a pleasure to be able to give some back.
> 
> –wpd

---

<div class="post-metadata">

**Author:** ![vahagn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/v/cc9497/32.png) [@vahagn](https://www.ruby-forum.com/u/vahagn)\
**Post date:** [January 2, 2009, 8:53pm UTC](https://www.ruby-forum.com/t/testing-a-post-request-with-correct-param/156723/6 "2009-01-02T20:53:42Z")

</div>

Hi guys and thanks a lot.

post ‘account/forgot’, :user =\> {:email =\> ‘removed\_email\_address@domain.invalid’}

is the deal. Patrick, if you could figure this out by putting print  
statements in your controller you’re a better Rails coder than me 🙂  
Did you mean:

def forgot  
puts "OPTIONS: " + options[:user] #method undefined!  
etc etc  
.  
.  
.  
end

?

@Phlip: The thing is, this is an integration test. And because this is  
an integration test (it is meant to mimic a real-life user’s interaction  
with the app) I would mean it is OK to have GET and POST inside one  
test. (In real life, I first GET the “forgot password” view by clicking  
a link. Then, I POST my email to that view, etc. I could split these two  
actions into two separate tests and then combine them under a third test  
by calling the first one, then the second one. But, the flow would be  
exactly the same as if the two were inside a single test! This is why I  
think it is not necessary to make the test more atomic than it is - as  
long as it covers one distinct “scenario” of user-app interaction).

What I do when I need to see the errors I get (those who result in  
failures and errors in my test) is use this statement which I find very  
productive:

assert\_response :success, “Errors on model: #any assert statement can be  
used  
#{assigns(:my\_model).errors.full\_messages.to\_sentence}”

That way, the errors appear in the terminal window that I run my  
commands from.

Hope this helps!

Cheers, Vahagn
