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

David Chelimsky dchelimsky at gmail.com
Wed Feb 13 18:22:34 EST 2008


On Feb 13, 2008 6:24 PM, Wes Shaddix <wshaddix at gmail.com> wrote:
>
>  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)


This is referencing the @current_user instance variable  here, not the
current_user method.

>
>  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)


And this is stubbing the current_user method.

So you want to change the line in the controller to:

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

Cheers,
David

>
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list