Настройка Warden для использования в спецификациях контроллера RSpec

я смог использовать Devise sign_in метод входа пользователя в мои спецификации контроллера. Но теперь, когда я удаляю Devise из своего приложения, я не совсем уверен, как получить аналогичную функциональность, работая с just Warden самостоятельно.

как я должен идти о создании spec/spec_helper.rb и связанной с spec/support/*.rb файлы, чтобы получить Warden работает в спецификации контроллера достаточно?

Я попытался настроить файл в spec/support/warden.rb С этими содержание:

RSpec.configure do |config|
  config.include Warden::Test::Helpers

  config.after do
    Warden.test_reset!
  end
end

тогда у меня есть before вызовы, подобные этому, для аутентификации user фабрика:

before { login_as FactoryGirl.create(:user) }

но вот ошибка, которую я продолжаю видеть:

NameError:
  undefined method `user' for nil:NilClass

эта ошибка восходит к my authenticate_user! метод в контроллере:

def authenticate_user!
  redirect_to login_path, notice: "You need to sign in or sign up before continuing." if env['warden'].user.nil?
end

Я был бы признателен за любые рекомендации, которые кто-либо может предоставить.

2 ответов


там основная проблема с тем, что вы пытаетесь сделать. Warden-промежуточное программное обеспечение стойки, но спецификации контроллера RSpec даже не включают стойку, поскольку эти типы спецификаций не предназначены для запуска полного стека приложений, а только кода контроллера. Вы можете протестировать промежуточное ПО с помощью отдельных тестов только для них, но в этом случае я не думаю, что имеет смысл проверять, что сам Warden работает.

чтобы проверить правильность настройки Warden, следует использовать спецификации запроса или спецификации интеграции (огурец, капибара или подобное).

хотя технически возможно издеваться над надзирателем в спецификациях контроллера, я думаю, что это не дает вам большой пользы, значительно увеличивая сложность вашего тестового кода. Имейте в виду, что Rack middleware предназначен для работы в прозрачном виде, так что это легко поменять middleware в и из, как вам нравится. Ваш контроллер не должен напрямую зависеть от Warden (за исключением, возможно,ApplicationController), на самом деле, так что зависимость от начальника на геймпаде-это признак нарушена инкапсуляция.

я столкнулся с этой же проблемой недавно, поэтому я надеюсь, что этот комментарий будет полезен.


Я не думал, что этот вопрос относится к моей ситуации, но это так:Stubbing Warden на тестах контроллера

как оказалось, Warden не входит в спецификации контроллера RSpec, поэтому вам нужно сделать некоторую магию, чтобы finagle его.

Кэнтаро Имаи ' s контроллер тест помощников для Warden сообщение в блоге было особенно полезным. Вот как я заставил его работать на RSpec.

шаг 1: создать spec/spec_helper/warden.rb и вставьте в это содержимое, которое Кентаро получил от Devise:

module Warden
  # Warden::Test::ControllerHelpers provides a facility to test controllers in isolation
  # Most of the code was extracted from Devise's Devise::TestHelpers.
  module Test
    module ControllerHelpers
      def self.included(base)
        base.class_eval do
          setup :setup_controller_for_warden, :warden if respond_to?(:setup)
        end
      end

      # Override process to consider warden.
      def process(*)
        # Make sure we always return @response, a la ActionController::TestCase::Behavior#process, even if warden interrupts
        _catch_warden {super} || @response
      end

      # We need to setup the environment variables and the response in the controller
      def setup_controller_for_warden
        @request.env['action_controller.instance'] = @controller
      end

      # Quick access to Warden::Proxy.
      def warden
        @warden ||= begin
          manager = Warden::Manager.new(nil, &Rails.application.config.middleware.detect{|m| m.name == 'Warden::Manager'}.block)
          @request.env['warden'] = Warden::Proxy.new(@request.env, manager)
        end
      end

      protected

      # Catch warden continuations and handle like the middleware would.
      # Returns nil when interrupted, otherwise the normal result of the block.
      def _catch_warden(&block)
        result = catch(:warden, &block)

        if result.is_a?(Hash) && !warden.custom_failure? && !@controller.send(:performed?)
          result[:action] ||= :unauthenticated

          env = @controller.request.env
          env['PATH_INFO'] = "/#{result[:action]}"
          env['warden.options'] = result
          Warden::Manager._run_callbacks(:before_failure, env, result)

          status, headers, body = warden.config[:failure_app].call(env).to_a
          @controller.send :render, :status => status, :text => body,
            :content_type => headers['Content-Type'], :location => headers['Location']

          nil
        else
          result
        end
      end
    end
  end
end

Шаг 2: на spec/spec_helper.rb внутри RSpec.configure заблокировать, добавьте эту строку, чтобы включить новый модуль:

config.include Warden::Test::ControllerHelpers, type: :controller

Шаг 3: при входе в before блок, используйте следующий синтаксис:

before { warden.set_user FactoryGirl.create(:user) }

Шаг 4: убедитесь, что вы ссылка request.env['warden'] в контроллерах, а не env['warden']. Последний не будет работа в спецификациях контроллера в test окружающая среда.

наконечник шляпы Кентаро Имаи, которому я должен пиво один день (или в другой жизни)!