Specs for controllers and rescue_from

Hey guys. My ApplicationController rescues
Mongoid::Errors::DocumentNotFound errors like this:

class ApplicationController < ActionController::Base
rescue_from Mongoid::Errors::DocumentNotFound,
:with => :resource_not_found

protected

def resource_not_found(error)
flash[:alert] = t(‘errors.resource_not_found’)
redirect_to root_url
end
end

Obviously, I need specs for this. However, I can’t figure out how this
should be specced.

Should I create a shared example group that expects the flash-alert
and redirect, and use it in every controller action that could
potentially raise this error? This seems right, but will be verbose.

Or, in each controller that could raise this error, should I create
one example group that raises this error and expects the flash-alert
and redirect? This seems right because the rescuing behaviour exists
within the controller rather than each action. However, it ignores the
possibility of an action rescuing the error.

Should I create a dummy controller with an action that raises this
error, and spec that? This would be akin to speccing
ApplicationController, though indirectly. This method was my first
inclination, but fails to provide specs for the other controllers that
inherit the rescuing behaviour.

How would you spec this? I’m all ears!
Nick

I had a similar problem in the past (with RSpec 1.x). I tend to create
what I call a BaseController in each namespace specifically for shared
behavior. The best example of this is

class Admin::BaseController < ApplicationController
before_filter :require_logged_in
before_filter :require_admin

 protected

 def require_admin
     redirect_to error_path(403) unless 

current_user.is_administrator
end
end

[:require_logged_in is defined in ApplicationController because it is
also used by User::BaseController.]

More comments inline.

On 2010-11-20 10:12 PM, Nick H. wrote:

 flash[:alert] = t('errors.resource_not_found')

I started to go this route as it seemed most appropriate to spec a
controller’s behavior in that controller, but since the behavior was
going to be the same in all such controllers, a shared example made
perfect sense. I was happily specing against the index action of such
controllers, until I came to one that didn’t have an index action.
Instead of putting in one just to be able to test, I tried figuring out
how to use an arbitrary action in the shared example. But that became
too complicated very quickly. There very well might be a way to do this,
but I was unable to get to it.

Or, in each controller that could raise this error, should I create
one example group that raises this error and expects the flash-alert
and redirect? This seems right because the rescuing behaviour exists
within the controller rather than each action. However, it ignores the
possibility of an action rescuing the error.

Could you not also spec it in actions that you see as possible sources
of the exception? This approach would certainly be most verbose, but
maybe you should start here and see what pattern develops that could
lead you down the proper path of refactoring.

Should I create a dummy controller with an action that raises this
error, and spec that? This would be akin to speccing
ApplicationController, though indirectly. This method was my first
inclination, but fails to provide specs for the other controllers that
inherit the rescuing behaviour.

Ultimately, I went this direction. I more or less applied the logic that
I would with a plugin: if the plugin is well tested and I trust it, do I
really need to test it wherever it is used? Here is what I ended up
with:

require ‘controller_helper’

describe Admin::BaseController do
should_descend_from ApplicationController
should_have_before_filter :require_logged_in
should_have_before_filter :require_admin
end

class Admin::BogusController < Admin::BaseController
def index
render :nothing => true
end
end

ActionController::Routing::Routes.draw do |map|
map.namespace :admin do |admin|
admin.resources :bogus
end
end

describe Admin::BogusController do
context ‘when the user is not logged in’ do
before(:each) { get :index }

     it 'should redirect to login path' do
         response.should redirect_to(login_path)
     end
 end

 context 'when accessed by administrative users' do
     before :each do
         setup_admin
         get :index
     end

     it 'should not redirect to error path 403' do
         response.should_not redirect_to(error_path(403))
     end

     should_succeed
 end

 context 'when accessed by non-administrative users' do
     before :each do
         setup_user
         get :index
     end

     it 'should redirect to error path 403' do
         response.should redirect_to(error_path(403))
     end
 end

end

I’m not sure if this is what I’d do today, but this did solve my problem
before. My preference would have been the shared examples, but I don’t
want my tests to be too complicated.

Peace,
Phillip

On Nov 20, 2010, at 10:12 PM, Nick H. wrote:

flash[:alert] = t(‘errors.resource_not_found’)

inherit the rescuing behaviour.

How would you spec this? I’m all ears!

http://relishapp.com/rspec/rspec-rails/v/2-1/dir/controller-specs/anonymous-controller

On Nov 21, 5:02pm, David C. [email protected] wrote:

http://relishapp.com/rspec/rspec-rails/v/2-1/dir/controller-specs/ano

Fantastic. Thanks, David!