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

回避策の 1 つは、ルーティング エンジンの制約を緩めることです。これはルーティングをバイパスしませんが、テストの作業を容易にします。

次のようなものを仕様に追加します。

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

ルーティングはコントローラーの仕様に関する個別の関心事ではないと私は主張します。その理由の1つは、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、またはあなたが実行したい同等の承認プロセスが期待どおりに機能していることです。その場合、1つのアクションのみをテストし、それが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 に答える