[rspec-users] Specing based on user roles

Mark Wilden mark at mwilden.com
Thu Nov 6 11:03:18 EST 2008


Mark Wilden to rspec-users
show details 7:46 AM (0 minutes ago)
Reply

- Show quoted text -
On Thu, Nov 6, 2008 at 7: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. What is a better way of writing such
> specs?
> --
> Posted via http://www.ruby-forum.com/.
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>

One thing I've been trying lately is to share shared spec (somewhat like
inheritance). I too have many tests that a essentially duplicates of each
other. So by factoring out commonalities and differences, I'd have something
like

// anybody_spec.rb
 module AnybodySpec
   describe 'anybody', :shared => true
end

// nonadmin_spec.rb
require 'anybody_spec'

describe 'a nonadmin'
  include AnyBodySpec
  it_should_behave_like 'anybody'
  before :each # login as a nonadmin
  # specs that apply to anyone, given the right setup
end

// admin_spec.rb
require 'anybody_spec'
module AdminSpec
  include AnyBodySpec
  describe 'an admin', :shared => true
    it_should_behave_like 'anybody'
    # specs that apply to any admin, given the right setup
end

describe 'admin'
  # specs that only apply to admins
end

// sysadmin_spec.rb
require 'admin_spec'
module SysAdminSpec
  include AdminSpec
  describe 'a sysadmin'
    it_should_behave_like 'an admin'
    # specs that apply to any sysadmin, given the right setup
end

describe 'sysadmin'
  # specs that only apply to sysadmins
end

This is all from memory, so it's not complete. But the idea is that you can
have shared specs behave_like other shared specs. before() is run from
bottom to top, so you can set @instance variables to parameterize the specs,
just making sure that an outer level spec doesn't overwrite an inner level
spec's variables.

I'm writing specs for a lot of different queries. There are three that group
by date, week or month - they're different in some ways and the same in a
lot of others. Those three are grouped by time period, which is the same in
some ways as grouping by an entity, and different from others. There are two
or three other types of queries, too, each sharing some stuff and being
completely different in other ways.

Using nested shared examples like this has massively reduced the duplication
in my spec code. And it's also guaranteed that all the specs get run on all
the code they apply to. Finally, it has suggested similar refactorings in
the code under test. It seems to be working well for me.

///ark
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20081106/89c58b44/attachment-0001.html>


More information about the rspec-users mailing list