Problem with before filters

Following is the scenario.

describe BbPostsController, “POST Create” do
context “Admin” do
fixtures :users, :bb_posts, :user_channels, :channels,
:channel_features
it “should save post” do
login_as(:amit)
# Added to pass before filters in controller
controller.stub!(:validate_channel).and_return(true)
controller.stub!(:is_feature_active).and_return(Blog)
controller.stub!(:load_categories).and_return(1)
@post = mock_model( BbPost, :body => “test_description”, :title
=> “test123”, :abstract => “test_abstract”, :channel_feature_id => “v1”,
:published => “1”, :bb_post_category_id => “1” )
BbPost.stub!(:new).and_return @post
@post.should_receive( :save )
post :create, {:bb_post => {:title => ‘test123’}}
response.should redirect_to( blog_bb_posts_url(:channel =>
@channel.brand_name) )
end

Following is the controller code:
class BbPostsController < ApplicationController
before_filter :login_required
before_filter :validate_channel
before_filter :manager_access_required
before_filter :is_feature_active
before_filter :load_categories, :only => [ :new, :edit, :create,
:update ]

BEFORE FILTER : Feature must active

def is_feature_active
@feature = @channel.channel_features.by_name( BLOG ).active.first
unless @feature
flash[ :notice ] = ‘Blog feature was not active.’
redirect_to requests_features_path
end
end

BEFORE FILTER : Load blog categories

def load_categories
# manager blog will not have admin specific categories
@categories = ( params[ :channel ].camelize == ADMIN_CHANNEL ) ?
BbPostCategory.visible : BbPostCategory.visible.without_admin
end

def create
params[ :bb_post ][ :brand_list ] = ADMIN_CHANNEL if params[
:bb_post ][ :brand_list ].blank?
p params
@bb_post = @feature.posts.new( params[ :bb_post ] )
@bb_post.user = current_user
# CREATE Channel Blog post
respond_to do |format|
if @bb_post.save
flash[ :notice ] = ‘Blog post was successfully created.’
format.html { redirect_to( blog_bb_posts_url ) }
format.xml { render :xml => @bb_post, :status => :created,
:location => @bb_post }
else
load_featured_posts if @bb_post.editorial?
format.html { render :action => “new” }
format.xml { render :xml => @bb_post.errors, :status =>
:unprocessable_entity }
end
end
end

Now if i run my specs,i get an error which says

NoMethodError in ‘BbPostsController POST Crete dmin should sve post’
You hve nil object when you didn’t expect it!
The error occurred while evluting nil.posts
Error comes at “@bb_post = @feature.posts.new( params[ :bb_post ] )”

Just above that line i tried to print params and i get following values:
#<BbPost:0x44d1cd8 @nme=“BbPost_1001”>
{“ction”=>“crete”, “controller”=>“bb_posts”,
“bb_post”=>{“brnd_list”=>“BrndPotio
n”, “title”=>“test123”}}

Can somebody help me with this
Also by using controller.stub!(:validate_channel).and_return(true) can
somebody tell me actually,what exactly happens here.How does it handle
before filters.

On Nov 2, 2009, at 3:35 AM, Amit K. wrote:

   controller.stub!(:is_feature_active).and_return(Blog)
 end

BEFORE FILTER : Feature must active

manager blog will not have admin specific categories

CREATE Channel Blog post

:unprocessable_entity }
end
end
end

Now if i run my specs,i get an error which says

NoMethodError in ‘BbPostsController POST Crete dmin should sve post’
You hve nil object when you didn’t expect it!
The error occurred while evluting nil.posts
Error comes at “@bb_post = @feature.posts.new( params[ :bb_post ] )”

This tells you that @feature is nil. This is because filter that
declares @feature and assigns it a value is being stubbed. Although
very common, using filters to set instance variables makes it
difficult to test in isolation.

I recommend pushing the model concerns to the model, and use filters
for application flow control concerns (like authentication/
authorization) in the controller. In this case, that would mean
eliminating the validate_channel, is_feature_active, and
load_categories filters and simply passing the params to the model.
I’m not sure of the models and relationships, but I’m imagining
something like:

def create
@bb_post = BbPost.new( params[ :bb_post ].merge(:user =>
current_user) )
respond_to do |format|
if @bb_post.save

All of the logic in the filters and before the assignment of @bb_post
can be managed in the BbPost model, where it is far easier to spec in
my experience.

If you don’t want to follow that recommendation, you’ll have to either
set up all the state you need in the database for each example, or do
more invasive setup like this:

controller.instance_eval { @feature = mock(‘feature’) }

before filters.
Filters are just methods that get called implicitly by the controller.
RSpec’s mocking framework doesn’t handle them in any special way (nor
does any test double frameowrk that I’m aware of). Stubs return
values. They do not set state on the object in question, which is why
if you stub is_feature_active, for example, that needs to be coupled
with code that sets the value of @feature on the controller (per above).

HTH,
David

On 2 Nov 2009, at 14:19, David C. wrote:

  # Added to pass before filters in controller
  response.should redirect_to( blog_bb_posts_url(:channel =>

:update ]

BEFORE FILTER : Load blog categories

@bb_post = @feature.posts.new( params[ :bb_post ] )
format.html { render :action => “new” }
The error occurred while evluting nil.posts
eliminating the validate_channel, is_feature_active, and

All of the logic in the filters and before the assignment of
@bb_post can be managed in the BbPost model, where it is far easier
to spec in my experience.

If you don’t want to follow that recommendation, you’ll have to
either set up all the state you need in the database for each
example, or do more invasive setup like this:

controller.instance_eval { @feature = mock(‘feature’) }

I’d just back this up to say that one of the major benefits of test-
driven-development is the guidance you get with your design. Mocking,
particularly, gives you really clear feedback on whether you have a
loosely-coupled OO design or not. If you’re finding your specs are
hard to write, and your mocks are unwieldy and complex, it’s always a
good idea to take a step back and think about whether your design
needs some work.

can
on the controller (per above).

HTH,
David


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

cheers,
Matt

+447974 430184