How can I call a different controller from within a function

From within a controller test, I can call a function in the controller like
this:

get :index

but how do I call a function in a different controller?

I want to do this for a couple reasons.
First I want to have my tests do a “real” login through my “user”
controller.
Second, my app supports redirects back to “where you were.” For
instance, if
a user goes to url A, then to url B, they might be redirected back to A.
If,
instead, they go to C, then to B, they’ll be redirected back to C. To
test
this functionality, I need to set the “original” URL by going to an URL
in
another controller (the A or C), then go to the URL in the controller
under
test, and see that the redirect is to the original controller.

I wrote some cheesy code to approximate the behavior I want. It looks
like
this:

class Test::Unit::TestCase
#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
#MES- Remake the request, but save the session
new_req = ActionController::TestRequest.new
new_req.session = @request.session
@request = new_req
end
end
end

and it can be called like this:

http_to_controller(:get, UserController.new, :show, { :id => user_id })

But it doesn’t work quite right. In particular, the URLs are not always
quite right, so a call to @request.request_uri returns an old value (in
this
example, it wouldn’t return the URL to the UserController method, it’d
return the URL to whatever the previous call was.

Any ideas? It seems like there’s got to be a cleaner and safer way to do
this, but I haven’t been able to come up with it.

On 17.11.2005, at 4.53, Michael S. wrote:

Second, my app supports redirects back to “where you were.” For
instance, if a user goes to url A, then to url B, they might be
redirected back to A. If, instead, they go to C, then to B,
they’ll be redirected back to C. To test this functionality, I
need to set the “original” URL by going to an URL in another
controller (the A or C), then go to the URL in the controller under
test, and see that the redirect is to the original controller.

You can split this up in parts.

In (say) posts_controller_test you test that the user is redirected
to the login action in user controller, unless @session[:user]
exists. You should also test that the “return address” is saved
somewhere (probably session, too, or you can also use the referrer).

Then, in the user controller tests, you test that if the return
address is set and login is valid, the user is redirected back to the
correct place in the app.

Back in posts_controller_test, you then check that if @session[:user]
exists, everything works fine without redirects to login system.

So you don’t really need to “go” to another url in your tests, as
long as you can test that the needed session vars are set and that
the redirection obeys them.

//jarkko

Hi there,

On 11/17/05, Michael S. [email protected] wrote:

but how do I call a function in a different controller?

I want to do this for a couple reasons.
First I want to have my tests do a “real” login through my “user”
controller.

Any ideas? It seems like there’s got to be a cleaner and safer way to do
this, but I haven’t been able to come up with it.

I would suggest that you approach the problem in a different way. I
find it much easier to test each controller/action in isolation from
other actions. Where an action requires state from a previous action I
pass the action in through the session parameter.

For example, most of the actions in my current application require
authentication. A client is authenticated if a valid user_id is stored
in the session so that value needs to be in session for action to be
successful. So an example where it is used would be the following that
tests creation of a comment;

post(:new, {:comment =>{:issue_id => 1, :description =>
description}}, {‘user_id’ => 1} )

You could invoke multiple actions from multiple controllers but I
would suggest that this makes test evolution hard and less fine
grained. Hope that helps!


Cheers,

Peter D.
RealityForge.org: http://www.realityforge.org