views:

800

answers:

2

Hello everyone,

I am trying to test my controller and maintain separation of concerns.

The first concern is "Who is able to execute which action?"
I am using authlogic for authentication and be9's acl9 for authorization. But this should not matter, all my authorization concerns are handled in a before_filter. I am testing such a before_filter by something similar to this:

describe SomeModelsController, "GET to index (authorization)" do
  before(:each) do
    @siteadmin = mock_model(User)
    @siteadmin.stub!(:has_role?).with("siteadmin", nil).and_return(true)
  end

  it "should grant access to a siteadmin" do
    controller.should_receive(:current_user).at_least(:once).and_return(@siteadmin)
    get :index
    response.should be_success
  end
end

This spec is working just fine!

Now, the second concern is "Does the action do what it is supposed to do?"
This does not involve checking authorization. The best/cleanest solution would be skipping that before_filter all together and just do something like:

describe SomeModelsController, "GET to index (functional)" do
  it "should find all Models" do
    Model.should_receive(:find).with(:all)
  end
end

Without having to worry about which user with wich role has to logged in first. Right now I solved it like that:

describe SomeModelsController, "GET to index (functional)" do
  before(:each) do
    @siteadmin = mock_model(User)
    @siteadmin.stub!(:has_role?).with("siteadmin", nil).and_return(true)
    controller.stub!(:current_user).and_return(@siteadmin)
   end

  it "should find all Models" do
    Model.should_receive(:find).with(:all)
  end
end

If I now decided that my siteadmin does not have the right to access the index action anymore, it would not only break one spec - namely the spec that HAS to break in such a case - but also the totally unrelated second spec.

I know this is basically a minor issue, but it would be nice if somebody could come up with an (elegant) solution!

+1  A: 

To skip the before filter:

controller.class.skip_before_filter :name_of_method_used_as_before_filter

The one caveat (mentioned the docs) is that this will only work for method-reference filters, not procs.

Alternatively, you could stub current_user.has_role?

describe SomeModelsController, "GET to index (functional)" do
  before(:each) do
    controller.current_user.stub!(:has_role?).and_return(true)
  end

  it "should find all Models" do
    Model.should_receive(:find).with(:all)
  end
end
Baldu
Thanks, didn't think about this one.If there's not way to skip the before_filter, this might be the best solution.
sebastiangeiger
Ok, I updated my answer. Hopefully that's what you needed.
Baldu
Nice, skipping the before filter works. The only downside is that acl9 installs a nameless lambda filter per default, so I have to force the creation of a named before_filter.
sebastiangeiger
A: 

How about just not doing a GET request? Try calling the controller method by itself.

controller.index
fernyb