I''m implementing an app that uses the salted login generator to
authenticate
users.
When a user visits other controllers in the app, they are redirected to the
login page (via a before_filter), which seems to work correctly.
To test these controllers with the controller-specific subclass of
Test::Unit::TestCase, most methods need to log in before proceeding with the
test. For example:
def test_show
# MUST LOG IN HERE, OR WILL BE REDIRECTED TO LOGIN PAGE
get :show, :id => 1
assert_response :success # WILL FAIL- THIS IS A REDIRECT
assert_template ''show''
end
I''d LIKE to do something like this to perform the login:
post :login, "user" => { "login" =>
''bob'', "password" => ''atest'' },
:controller => "user"
but it seems like the controller argument in the hash isn''t recognized
(where''s the doc or source for ''post''? Being a
newbie, I couldn''t find it.)
It seems like the [X]ControllerTest class that was generated by Rails only
knows how to send messages to itself, rather than to other controllers.
Is there a good way to do this?
P.S.
I tried to work around this by adding my own methods to do this, which look
like this:
def login(username = ''bob'', password =
''atest'')
if username.is_a? User
username = username.login
end
#MES- Post login information to the login method in the user controller
post_to_controller UserController.new, :login, "user" => {
"login" =>
username, "password" => password }
assert_session_has ''user'', "Login failed for user
#{username} with password
#{password}"
end
#MES- A helper that ''posts'' the indicated information
def post_to_controller(controller, action, params = {})
http_to_controller(:post, controller, action, params)
end
#MES- Send an HTTP message to the indicated controller via
# the indicated method
def http_to_controller(method, controller, action, params)
#MES- Store the current controller
backup_controller = @controller
begin
#MES- Swap in the indicated controller
@controller = controller
#MES- Send the HTTP message
self.send(method, action, params)
ensure
#MES- Swap back in the controller
@controller = backup_controller
end
end
This actually DOES work, but it seems to mess up the processing of
redirects. When I run a test like this:
def test_create
login
initial_num_Xs = X.count
#MES- View X, to have something to redirect back to
get_to_controller(Y.new, :show, { :id => 1 })
#MES- Create an X
post :create, :x => {}
#MES- Check that we were redirected properly, and that the number of Xs has
grown
assert_redirected_to :controller => ''Y'' , :action =>
''show'' , :id => 1
assert_equal initial_num_Xs + 1, X.count
end
I get a failure on the assert_redirected_to, like this:
1) Failure:
test_create(XControllerTest)
[c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.9.1/lib/action_controller/assertions.rb:88:in
`assert_redirected_to'' test/functional/X_controller_test.rb:98:in
`test_create'']:
response is not a redirection to all of the options supplied (redirection is
<"http://test.host/user/login?user=passwordatestloginbob">)
It seems like the response redirect information is getting cached and is not
replaced by subsequent requests?
Any thoughts? Thanks!
_______________________________________________
Rails mailing list
Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
http://lists.rubyonrails.org/mailman/listinfo/rails
I''m not sure if this will be a good solution for you, but what I did
when confronted with this problem is just write one test that makes
sure the non-logged in user gets redirected from the controller to
the login. Then, for all subsequent tests of the controller, I
created some helpers in test_helper.rb:
def auth_get(action, params = {}, session = { :user => @bob })
get action, params, session
end
def auth_post(action, params = {}, session = { :user => @bob })
post action, params, session
end
On Sep 15, 2005, at 3:59 PM, Michael Smedberg wrote:
> I''m implementing an app that uses the salted login generator to
> authenticate users.
>
> When a user visits other controllers in the app, they are
> redirected to the login page (via a before_filter), which seems to
> work correctly.
>
> To test these controllers with the controller-specific subclass of
> Test::Unit::TestCase, most methods need to log in before proceeding
> with the test. For example:
>
> def test_show
> # MUST LOG IN HERE, OR WILL BE REDIRECTED TO LOGIN PAGE
> get :show, :id => 1
>
> assert_response :success # WILL FAIL- THIS IS A REDIRECT
> assert_template ''show''
> end
>
> I''d LIKE to do something like this to perform the login:
>
> post :login, "user" => { "login" =>
''bob'', "password" =>
> ''atest'' }, :controller => "user"
>
> but it seems like the controller argument in the hash isn''t
> recognized (where''s the doc or source for
''post''? Being a newbie,
> I couldn''t find it.) It seems like the [X]ControllerTest class
> that was generated by Rails only knows how to send messages to
> itself, rather than to other controllers.
>
> Is there a good way to do this?
>
>
> P.S.
>
> I tried to work around this by adding my own methods to do this,
> which look like this:
>
> def login(username = ''bob'', password =
''atest'')
> if username.is_a? User
> username = username.login
> end
> #MES- Post login information to the login method in the user
> controller
> post_to_controller UserController.new, :login, "user" =>
> { "login" => username, "password" => password }
> assert_session_has ''user'', "Login failed for
user #{username}
> with password #{password}"
> end
>
> #MES- A helper that ''posts'' the indicated information
> def post_to_controller(controller, action, params = {})
> http_to_controller(:post, controller, action, params)
> end
>
> #MES- Send an HTTP message to the indicated controller via
> # the indicated method
> def http_to_controller(method, controller, action, params)
> #MES- Store the current controller
> backup_controller = @controller
> begin
> #MES- Swap in the indicated controller
> @controller = controller
>
> #MES- Send the HTTP message
> self.send(method, action, params)
> ensure
> #MES- Swap back in the controller
> @controller = backup_controller
> end
> end
>
> This actually DOES work, but it seems to mess up the processing of
> redirects. When I run a test like this:
>
> def test_create
> login
>
> initial_num_Xs = X.count
>
> #MES- View X, to have something to redirect back to
> get_to_controller(Y.new, :show, { :id => 1 })
>
> #MES- Create an X
> post :create, :x => {}
>
> #MES- Check that we were redirected properly, and that the
> number of Xs has grown
> assert_redirected_to :controller => ''Y'' , :action
=>
> ''show'' , :id => 1
> assert_equal initial_num_Xs + 1, X.count
> end
>
> I get a failure on the assert_redirected_to, like this:
>
> 1) Failure:
> test_create(XControllerTest)
> [c:/ruby/lib/ruby/gems/1.8/gems/actionpack-1.9.1/lib/
> action_controller/assertions.rb:88:in `assert_redirected_to'' test/
> functional/X_controller_test.rb:98:in `test_create'']:
> response is not a redirection to all of the options supplied
> (redirection is <"http://test.host/user/login?
> user=passwordatestloginbob">)
>
> It seems like the response redirect information is getting cached
> and is not replaced by subsequent requests?
>
> Any thoughts? Thanks!
> _______________________________________________
> Rails mailing list
> Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>
Michael,
I usually set up a method in test_helper called login_as_admin that
works as though it''s in the login controller, and then in the
functional tests have this as my setup method:
--
def setup
# make sure we are authenticated
@controller = Admin::LoginController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
login_as_admin
@controller = Admin::ThisController.new
end
--
Don''t know about the specifics of the generator you are using but i
hope that helps
As an aside, if you want to inspect the session in your tests, do this as well
--
@session = ActionController::TestSession.new
@request.session = @session
--
Cheers,
Dan
Thanks for the help!
It took me a while, but I think I figured this out.
The problem is that information is cached in the @request object the first
time it''s used. On subsequent requests, the URL information is not
refreshed. So you you do a "get A", then a "get B", the
@request.request_urlwill be the one from A. The solution I found is to
make a new request, and
copy the session from the old request to the new request (there may be an
easier way to flush the request, but I couldn''t find it-
@request.recycle!
didn''t seem to do it.)
Here''s some code that displays the problem and my solution (I put this
in a
file called ''test\functional\url_test.rb''):
require File.dirname(__FILE__) + ''/../test_helper''
class ControllerA < ApplicationController
def do_nothing
end
def do_nothing_2
p "*** My URL is #{@request.request_uri} and I''m in function
do_nothing_2"
end
end
class URLTest < Test::Unit::TestCase
def test_url
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@controller = ControllerA.new
# Get an URL
get :do_nothing
# Get a different URL
get :do_nothing_2
# Now remake the request and try again
new_req = ActionController::TestRequest.new
new_req.session = @request.session
@request = new_req
get :do_nothing_2
end
end
When I run it, here''s the output:
Loaded suite test/functional/url_test
Started
"*** My URL is /controller_a/do_nothing and I''m in function
do_nothing_2"
"*** My URL is /controller_a/do_nothing_2 and I''m in function
do_nothing_2"
.
Finished in 0.078 seconds.
Note that in the first call to ''do_nothing_2'', the stated URL
doesn''t match
the function name, but in the second call (after clearing the @request), the
value matches.
This seems kinda hacky to me, but it seems to work correctly.
Thanks again for your help!
On 9/15/05, Dan Sketcher
<dansketcher-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
wrote:>
> Michael,
>
> I usually set up a method in test_helper called login_as_admin that
> works as though it''s in the login controller, and then in the
> functional tests have this as my setup method:
>
> --
> def setup
> # make sure we are authenticated
> @controller = Admin::LoginController.new
> @request = ActionController::TestRequest.new
> @response = ActionController::TestResponse.new
>
> login_as_admin
>
> @controller = Admin::ThisController.new
> end
> --
>
> Don''t know about the specifics of the generator you are using but
i
> hope that helps
>
> As an aside, if you want to inspect the session in your tests, do this as
> well
> --
> @session = ActionController::TestSession.new
> @request.session = @session
> --
>
> Cheers,
> Dan
>
_______________________________________________
Rails mailing list
Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org
http://lists.rubyonrails.org/mailman/listinfo/rails