[rspec-users] How do I mock out the before :login_required method?

Wes Shaddix wshaddix at gmail.com
Wed Feb 13 18:24:32 EST 2008


David Chelimsky wrote:
> On Feb 13, 2008 6:03 PM, Wes Shaddix <wshaddix at gmail.com> wrote:
>   
>> Jarkko Laine wrote:
>>     
>>> On 13.2.2008, at 5.12, Wes Shaddix wrote:
>>>
>>>       
>>>> I have a GroupController class that inherits from a SecuredController
>>>> which have a before filter (before_filter :login_required). This is
>>>> using the restul authentication system. I want to mock out the
>>>> login_required method so that my GroupController actions don't get
>>>> redirected to /sessions/new but I cant figure it out. Here is what I
>>>> have so far that doesn't work. Any help would be most appreciated.
>>>>
>>>> require File.dirname(__FILE__) + '/../spec_helper'
>>>>
>>>> describe GroupsController do
>>>>
>>>>  before(:each) do
>>>>
>>>>   # mock and stub the Group model methods
>>>>   @group = mock_model(Group)
>>>>   Group.stub!(:search_with_paginate).and_return(@group)
>>>>
>>>>
>>>>
>>>>    # since this is a secured controller, we have to mock the security
>>>> system too
>>>>
>>>>    @current_user = mock_model(User, :id => 1)
>>>>
>>>>    self.stub!(:login_required).and_return(:false)
>>>>
>>>>    self.stub!(:current_user).and_return(@current_user)
>>>>
>>>>  end
>>>>
>>>>
>>>>
>>>>  def do_get
>>>>
>>>>    get :index
>>>>
>>>>  end
>>>>
>>>>
>>>>
>>>>  it "should be successful" do
>>>>
>>>>    assigns[:page] = 1
>>>>
>>>>    assigns[:search] = ""
>>>>
>>>>    do_get
>>>>
>>>>    puts response.headers
>>>>
>>>>    response.should be_success
>>>>
>>>>  end
>>>>
>>>> end
>>>>
>>>> The error I get is
>>>> NoMethodError in 'GroupsController should be successful'
>>>> You have a nil object when you didn't expect it!
>>>> You might have expected an instance of ActiveRecord::Base.
>>>> The error occurred while evaluating nil.[]=
>>>>         
>>> What do you expect the assigns[:... lines to do? If you mean to use
>>> them as url parameters, you have to pass them to the get method
>>> (through do_get in this case). assigns is a hash that contains all the
>>> instance variables set in the controllers. So if you say "@foo =
>>> "bar"" in your controller action, you can spec it in a controller view
>>> like this: assigns[:foo].should == "bar". However, afaik you're not
>>> supposed to write into that hash in your controller specs. On the
>>> other hand, in the view specs you *do* need a way to set instance
>>> variables available in the views, and there you can use the assigns
>>> for that. So in a view spec corresponding to my previous example, you
>>> would want the instance variable @foo to be there so you would say
>>> "assigns[:foo] = 'bar'" in your before block.
>>>
>>> That said, I'm not a fan of stubbing the login_required method.
>>> Instead, I have created a login_as method in my spec_helper that I use
>>> whenever I want to spec something to happen when a logged in user does
>>> something (note that I also use the acl_system2 plugin for roles):
>>>
>>>   def login_as(role)
>>>     @role = mock_model(Role, :title => role.to_s)
>>>     @current_user = mock_user({:roles => [@role]})
>>>
>>>     [:admin, :organizer, :client, :teacher].each do |r|
>>>       @current_user.stub!(:has_role?).with(r).and_return(role == r ?
>>> true : false)
>>>     end
>>>
>>>     if defined?(controller)
>>>       controller.send :current_user=, @current_user
>>>     else
>>>       template.stub!(:logged_in?).and_return(true)
>>>       template.stub!(:current_user).and_return(@current_user)
>>>     end
>>>   end
>>> end
>>>
>>> This is a bit simplified but it works for me pretty well with
>>> restful_authentication. Normally you would say something like
>>> "login_as(:admin)" in a before block in controller and view specs.
>>>
>>> //jarkko
>>>
>>> --
>>> Jarkko Laine
>>> http://jlaine.net
>>> http://dotherightthing.com
>>> http://www.railsecommerce.com
>>> http://odesign.fi
>>>
>>>
>>> ------------------------------------------------------------------------
>>>
>>> _______________________________________________
>>> rspec-users mailing list
>>> rspec-users at rubyforge.org
>>> http://rubyforge.org/mailman/listinfo/rspec-users
>>>       
>> So, if I update my code to the following, I still get an exception,
>> although it is a different one. I really wish I understood how to
>> determine the actual call chain that is going on ... what object is nil
>> in this case (see error message below the code)?
>>     
>
> It should give you a file/line number, which should point you to the
> offensive line. FWIW, this is the same message you'd get using any
> framework, as it comes from Rails, not RSpec.
>
>   
>> require File.dirname(__FILE__) + '/../spec_helper'
>>
>> describe GroupsController do
>>
>>   before(:each) do
>>     # mock and stub the Group model methods
>>     @group = mock_model(Group)
>>     Group.stub!(:search_with_paginate).and_return(@group)
>>
>>     # since this is a secured controller, we have to mock the security
>> system too
>>     @current_user = mock_model(User, :id => 1)
>>     controller.stub!(:login_required).and_return(:true)
>>     controller.stub!(:current_user).and_return(@current_user)
>>   end
>>
>>   def do_get
>>     get :index
>>   end
>>
>>   it "should be successful" do
>>     do_get
>>     puts response.headers
>>     response.should be_success
>>   end
>>
>> end
>>
>> Exception : RuntimeError in 'GroupsController should be successful'
>> Called id for nil, which would mistakenly be 4 -- if you really wanted
>> the id of nil, use object_id
>>
>>
>> _______________________________________________
>> rspec-users mailing list
>> rspec-users at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/rspec-users
>>
>>     
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>   
Gotcha ... this is the offending line in my GroupsController

 @groups = Group.search_with_paginate(params[:page], params[:search], 
@current_user.id)

Which I'm sure is the @current_user.id. Where I'm confused is that I 
thought the following line in my GroupsController_spec would intercept 
this call and return the mock current_user instance:
    @current_user = mock_model(User, :id => 1)
    controller.stub!(:login_required).and_return(:true)
    controller.stub!(:current_user).and_return(@current_user)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://rubyforge.org/pipermail/rspec-users/attachments/20080213/3c14965a/attachment.html 


More information about the rspec-users mailing list