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: <form action="/account/forgot" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="b17df8ef7db06d17204142dfc501ff77256caa81" /></div> <p>Enter email address: <br /> <input id="user_email" name="user[email]" size="30" type="text" /></p> <input name="commit" type="submit" value="Email new password" /> </form> 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'', ''joe-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org'' #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 :-) -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ 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 rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Thu, Jan 1, 2009 at 5:25 PM, Vahagn Hayrapetyan < rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > 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 >> 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'', ''joe-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org'' #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.[]"> > >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 => ''joe-hcDgGtZH8xNBDgjK7y7TUQ@public.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]. Hope this helps. --wpd --~--~---------~--~----~------------~-------~--~----~ 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 rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
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." > endAll 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 farPutting 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.> ''joe-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org > <mailto:joe-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org>'' #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 rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Hi guys and thanks a lot. post ''account/forgot'', :user => {:email => ''joe-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org''} 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 -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ 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 rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Fri, Jan 2, 2009 at 2:53 PM, Vahagn Hayrapetyan < rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > Hi guys and thanks a lot. > > post ''account/forgot'', :user => {:email => ''joe-hcDgGtZH8xNBDgjK7y7TUQ@public.gmane.org''} > > 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 > .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 --~--~---------~--~----~------------~-------~--~----~ 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 rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
... and I''m looking forward to the day I''m able to give back, as well. / V. Patrick Doyle wrote:> On Fri, Jan 2, 2009 at 2:53 PM, Vahagn Hayrapetyan < > rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> 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-- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ 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 rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---