[rspec-users] Specing based on user roles

David Chelimsky dchelimsky at gmail.com
Thu Nov 6 11:01:28 EST 2008


On Thu, Nov 6, 2008 at 10:02 AM, Fernando Perez <lists at ruby-forum.com> wrote:
> On my website each user can have the following roles:
>
> 1) Not logged in
>
> 2) Logged in
>  - active
>  - administrator
>  - sysadministrator
>
>
>
> How would you write DRY specs to test each action of a controller?
>
> Currently I am doing somethings that looks like:
> --
> describe 'a non admin is signed in', :shared => true do
>  before(:each) do
>    @current_user = mock_model(User, :id => 1, :state => 'active')
>    controller.stub!(:current_user).and_return(@current_user)
>    @current_user.should_receive(:administrator?).and_return(false)
>    @current_user.should_receive(:sysadministrator?).and_return(false)
>  end
> end
>
> describe 'an administrator is signed in', :shared => true do
>  before(:each) do
>    @current_user = mock_model(User, :id => 1, :state =>
> 'administrator')
>    controller.stub!(:current_user).and_return(@current_user)
>    @current_user.should_receive(:administrator?).and_return(true)
>  end
> end
>
> describe Admin::OrdersController, 'index' do
>
>  describe "A non admin wants to have access" do
>    it_should_behave_like 'a non admin is signed in'
>
>    it "should redirect" do
>      get :index
>      response.should redirect_to(products_url)
>    end
>  end
>
>  describe "An admin wants to have access" do
>    it_should_behave_like 'an administrator is signed in'
>
>    it "should render index page" do
>      controller.should_receive(:select_date_initializer).with({},nil)
>      Order.should_not_receive(:admin_find_from_params)
>
>      get :index
>    end
>
>    it "should accept search params on index page" do
>      Order.should_receive(:admin_find_from_params).with('test.host',
> {}, {})
>
>      get :index, :commit => 'Search'
>    end
>  end
>
> end # describe Admin::OrdersController, 'index'
> ---
>
> I didn't test for the sysadministrator as it would force me to repeat
> all the tests for administrator, basically a sysadministrator has
> administrator rights and more.

And why wouldn't you want to test that?

> What is a better way of writing such specs?

I've really moved away from shared example groups and started writing
more targeted macros. So I might do something like this:

def for_roles *roles
  roles.each do |role|
    before(:each) { login_as role }
    yield
  end
end

describe OrdersController do
  describe "GET index" do
    for_roles :admin, :sysadmin do |role|
      it "..." do ... end
    end
    for_roles :sysadmin do |role|
      it "..." do ... end
    end
  end

  describe "GET edit" do
    for_roles :admin, :sysadmin do |role|
      it "..." do ... end
    end
    for_roles :sysadmin do |role|
      it "..." do ... end
    end
  end
end

When you're doing this sort of thing, it is crucial that you keep
things organized so that individual actions can change independently
as requirements change. This is the thing that most people fail to
realize when they try to DRY things up.

This scheme makes it easy when we decide to remove a privilege from
admin but keep it in sysadmin. Just move that example (it "...") to
the other for_roles block.

WDYT?


More information about the rspec-users mailing list