Testing ApplicationController with Sessions


#1

I have a method in my application controller that I would like to test.
The controller looks like this:

class ApplicationController < ActionController::Base

def redirect_back_or_default(default="/")
session[:return_to] ? redirect_to_url(session[:return_to]) :
redirect_to(default)
session[:return_to] = nil
end

end

(thx Rick :slight_smile:

Anyway, I want to create an isolated functional test for the
redirect_back_or_default method.

I created a new functional test (application_controller_test.rb):

require File.dirname(FILE) + ‘/…/test_helper’
require ‘application’

Re-raise errors caught by the controller.

class ApplicationController; def rescue_action(e) raise e end; end

class ApplicationControllerTest <Test::Unit::TestCase

def setup
@controller = ApplicationController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@default_url = “/”
end

def test_should_redirect_to_default
@controller.redirect_back_or_default
end
end

This test fails (yes, I realize that I don’t have any assertions yet
:-). The error I receive is:

  1. Error:
    test_should_redirect_to_default(ApplicationControllerTest):
    NoMethodError: You have a nil object when you didn’t expect it!
    You might have expected an instance of Array.
    The error occurred while evaluating nil.[]

The nil error pertains to the session object. So, can anyone provide
direction on how to go about testing this method without involving other
controllers?

Any help appreciated.


#2

class ApplicationControllerTest <Test::Unit::TestCase

def setup
@controller = ApplicationController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@default_url = “/”
end

def test_should_redirect_to_default
@controller.redirect_back_or_default
end
end

This test fails (yes, I realize that I don’t have any assertions yet
:-). The error I receive is:

  1. Error:
    test_should_redirect_to_default(ApplicationControllerTest):
    NoMethodError: You have a nil object when you didn’t expect it!
    You might have expected an instance of Array.
    The error occurred while evaluating nil.[]

The nil error pertains to the session object. So, can anyone provide
direction on how to go about testing this method without involving other
controllers?

Any help appreciated.

Don’t you want to do

get :redirect_back_or_default

instead of invoking the method directly on the controller?

Stephan


#3

Chris K. wrote:

Any help appreciated.

Don’t you want to do

get :redirect_back_or_default

instead of invoking the method directly on the controller?

Stephan

Is a get the proper way to handle this test? I will never actually make
a direct :get call to this method. It is just a helper method that I
want all of my controllers to inherit. I would prefer to build a test
that is in line with how the application will be used, i.e. my
controllers make a method call to redirect_back_or default vs. creating
an http get.

Here is a simple example of how the method would be used:

class UsersController < ApplicationController

def create
@user = User.new( params[:user] )

if @user.save
  redirect_back_or_default
else
  flash[:notice] = "Could not create user"
end

end

end

redirect_back_or_default could be used in many places, so I don’t want
to test it the context of every controller that makes the call.

Ok I was also wondering about that.

If you get a nil, you could initialize the field just for this test
then.

@controller.instance_eval

and set up @session = {}, define session reader and session[] writer
methods

Stephan


#4

If you get a nil, you could initialize the field just for this test
then.

@controller.instance_eval

and set up @session = {}, define session reader and session[] writer
methods

Yes, like this

@controller.instance_eval "@session = {} "
@controller.instance_eval "def session ; @session ; end "

then you could access the method in question.

Stephan


#5

If you get a nil, you could initialize the field just for this test
then.

@controller.instance_eval

and set up @session = {}, define session reader and session[] writer
methods

Yes, like this

@controller.instance_eval "@session = {} "
@controller.instance_eval "def session ; @session ; end "

then you could access the method in question.

Stephan

Unfortunately, I think the solution may be a bit more involved than
that. Here is the current test:

def test_should_redirect_to_default
@controller.instance_eval "@session = {} "
@controller.instance_eval "def session ; @session ; end "
@controller.redirect_back_or_default
assert_redirected_to “/”
end

and the result

test_should_redirect_to_default(ApplicationControllerTest):
NoMethodError: You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.protocol
…/config/…/vendor/rails/actionpack/lib/action_controller/base.rb:977:in
`redirect_to’

The method in the application controller is actually going to try to do
a redirect:

session[:return_to] ? redirect_to_url(session[:return_to]) :

I don’t know enough about the rails http internals yet to understand
exactly where I’m missing the boat. Is there some more internal
plumbing that needs to be instantiated?
redirect_to(default)


#6

Any help appreciated.

Don’t you want to do

get :redirect_back_or_default

instead of invoking the method directly on the controller?

Stephan

Is a get the proper way to handle this test? I will never actually make
a direct :get call to this method. It is just a helper method that I
want all of my controllers to inherit. I would prefer to build a test
that is in line with how the application will be used, i.e. my
controllers make a method call to redirect_back_or default vs. creating
an http get.

Here is a simple example of how the method would be used:

class UsersController < ApplicationController

def create
@user = User.new( params[:user] )

if @user.save
  redirect_back_or_default
else
  flash[:notice] = "Could not create user"
end

end

end

redirect_back_or_default could be used in many places, so I don’t want
to test it the context of every controller that makes the call.


#7

Chris K. wrote:

:
:
and the result

test_should_redirect_to_default(ApplicationControllerTest):
NoMethodError: You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.protocol
…/config/…/vendor/rails/actionpack/lib/action_controller/base.rb:977:in
`redirect_to’

The method in the application controller is actually going to try to do
a redirect:

session[:return_to] ? redirect_to_url(session[:return_to]) :

I don’t know enough about the rails http internals yet to understand
exactly where I’m missing the boat. Is there some more internal
plumbing that needs to be instantiated?
redirect_to(default)

Ok, maybe you can live with redefining the redirect_to_url as well for
your testing @controller instance.

@controller.instance_eval " @redirected_to "
@controller.instance_eval " def redirect_to(a) @redirected_to = a ; end
"
@controller.instance_eval " def redirected_to @redirected_to ; end "

and probably a little more.

Then you can pick up the result with asserts.

But also, you probably want to test this action as it impacts the
UsersController; meaning how the UsersController acts is what matters,
not
so much what the ApplicationController does.

Stephan


#8

Chris K. wrote:

If you get a nil, you could initialize the field just for this test
then.

@controller.instance_eval

and set up @session = {}, define session reader and session[] writer
methods

Yes, like this

@controller.instance_eval "@session = {} "
@controller.instance_eval "def session ; @session ; end "

then you could access the method in question.

Stephan

Unfortunately, I think the solution may be a bit more involved than
that. Here is the current test:

def test_should_redirect_to_default
@controller.instance_eval "@session = {} "
@controller.instance_eval "def session ; @session ; end "
@controller.redirect_back_or_default
assert_redirected_to “/”
end

and the result

test_should_redirect_to_default(ApplicationControllerTest):
NoMethodError: You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.protocol
…/config/…/vendor/rails/actionpack/lib/action_controller/base.rb:977:in
`redirect_to’

The method in the application controller is actually going to try to do
a redirect:

session[:return_to] ? redirect_to_url(session[:return_to]) :

I don’t know enough about the rails http internals yet to understand
exactly where I’m missing the boat. Is there some more internal
plumbing that needs to be instantiated?
redirect_to(default)

The line in actionpack/lib/action_controller/base.rb (977) throwing the
error is:

redirect_to(request.protocol + request.host_with_port + options)

So, I guess the question is how do I mock up the entire request/response
process and test this method in isolation?