3

我正在尝试单独测试我的控制器的动作链。具体来说,我想确保我想要的行为适用于我的所有控制器的操作。例如,测试我的所有操作是否需要身份验证:

context "when not authenticated" do

  # single case
  describe "GET index" do
    it "responds with 401" do
      get :index
      response.code.should be(401)
    end
  end

  # all of them...
  described_class.action_methods.each do |action|
    ['get', 'put', 'post', 'delete', 'patch'].each do |verb|
      describe "#{verb.upcase} #{action}" do
        it "responds with 401" do
          send verb, action
          response.code.should == "401"
        end
      end
    end   
  end

end

我希望这会起作用,但事实并非如此。我得到一些ActionController::RoutingErrors。这是因为我的一些路线需要参数,在某些情况下我没有提供它们(比如当我打电话时post :create)。我明白了。但我不明白的是:有什么关系!?

对于这些测试,路由是一个单独的问题。我关心我的行动链,而不是我的请求(这就是我所拥有routing specsrequest specs追求的)。在这个级别上,我不需要担心我的路线限制。

所以我的问题是:有没有办法只测试动作链而不模拟请​​求?

编辑:一些研究

看起来路线正在TestCase#process 中进行。这是必要的吗?

4

2 回答 2

6

一种解决方法是放松路由引擎的约束。这不会绕过路由,但确实可以更轻松地进行测试。

在您的规格中添加如下内容:

before(:all) do
  Rails.application.routes.draw { match ':controller(/:action)' }
end
after(:all) do
  Rails.application.reload_routes!
end

虽然严格来说不是这个问题的答案,但它可能是一个足够好的解决方法。

于 2013-03-14T17:45:15.733 回答
2

我认为路由不是控制器规范的单独关注点。原因之一是根据传递到 url 中的值将值添加到 params 哈希中,并且控制器中的代码可能取决于这些值。

无论如何,我假设您在ApplicationController. 单独测试每个控制器似乎有点多余。这是我的做法:

require "spec_helper"

describe ApplicationController do
  describe "require_current_user" do
    ACTIONS_AND_VERBS = [
      [:index,   :get],
      [:show,    :get],
      [:new,     :get],
      [:create,  :post],
      [:edit,    :get],
      [:update,  :put],
      [:destroy, :delete],
    ]

    controller do      
      ACTIONS_AND_VERBS.each do |action, _|
        define_method(action) do
        end
      end
    end

    ACTIONS_AND_VERBS.each do |action, verb|
      describe "#{verb.to_s.upcase} '#{action}'" do
        it "should be successful" do
          send(verb, action, id: -1)
          response.code.should eq("401")
        end
      end
    end
  end
end

在我的ApplicationController我会有类似的东西......

class ApplicationController < ActionController::Base
  protect_from_forgery

  before_filter :require_current_user

  def require_current_user
    head :unauthorized
  end
end

编辑:如果我理解正确,我们真正测试的是您的require_current_user,或您想要进行的任何等效授权过程,是否按预期工作。在这种情况下,我们可以只测试一个动作,并相信它before_filter可以正常工作。

require "spec_helper"

describe ApplicationController do
  describe "require_current_user" do
    controller do
      def index
      end
    end

    it 'should head unauthorized for unauthorized users' do
      get :index
      response.code.should eq("401")
    end
  end
end
于 2013-03-14T17:10:30.057 回答