Rails 中的 RSpec:如何跳过 before_filter?

发布于 2024-08-11 10:27:59 字数 1542 浏览 7 评论 0原文

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

首先关心的是“谁能够执行哪个操作?”
我使用authlogic进行身份验证,be9的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

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

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

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 which 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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

氛圍 2024-08-18 10:27:59

要跳过之前的过滤器:

controller.class.skip_before_filter :name_of_method_used_as_before_filter

一个警告(提到了文档 )是,这仅适用于方法引用过滤器,不适用于过程。

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

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
夏了南城 2024-08-18 10:27:59

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

您可以简单地从过滤器链中删除匹配的 Proc,如下所示(测试: :单位示例):

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

Old question, but I had to solve this just recently. This will only work for Rails 3.1, for earlier versions you should replace _process_action_callbacks with filter_chain (untested)

You can simply delete a matching Proc from the filter chain like so (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
向日葵 2024-08-18 10:27:59

不执行 GET 请求怎么样?
尝试单独调用控制器方法。

controller.index

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

controller.index
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文