Rails中的RSpec:如何跳过before_filter?

时间:2009-11-20 17:43:10

标签: ruby-on-rails rspec separation-of-concerns before-filter

我正在尝试测试我的控制器并保持关注点分离。

第一个问题是“谁能够执行哪个行动?”
 我使用 authlogic 进行身份验证,使用 be9's acl9 进行授权。但这并不重要,我的所有授权问题都在before_filter处理。我正在通过与此类似的东西测试这样的before_filter

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

此规范工作正常!

现在,第二个问题是“行动是否按预期进行?”
这不涉及检查授权。最好/最干净的解决方案是将before_filter全部一起跳过,然后执行以下操作:

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

无需担心哪个角色的用户必须先登录。现在我解决了这个问题:

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

如果我现在决定我的siteadmin无权再访问索引操作,那么它不仅会破坏一个规范 - 即在这种情况下必须破坏的规范 - 而且还有完全不相关的第二个规范。

我知道这基本上是一个小问题,但如果有人想出一个(优雅的)解决方案会很好!

3 个答案:

答案 0 :(得分:34)

要跳过前过滤器:

controller.class.skip_before_filter :name_of_method_used_as_before_filter

一个警告(mentioned the docs)是这只适用于方法参考过滤器,而不是过程。

或者,您可以存根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

答案 1 :(得分:0)

老问题,但最近我不得不解决这个问题。这仅适用于Rails 3.1,对于早期版本,您应将_process_action_callbacks替换为filter_chain(未经测试)

您可以简单地从过滤器链中删除匹配的Proc,如下所示(Test :: Unit example):

class RandomControllerTest < ActionController::TestCase
  def setup
    @controller.class._process_action_callbacks.each do |f|
      @controller.class._process_action_callbacks.delete(f) if f.raw_filter.to_s.match(/**<match for your proc>**/)
    end
  end
end

答案 2 :(得分:-9)

如何不做GET请求? 尝试单独调用控制器方法。

controller.index