Как эмулировать вход в систему для тестов контроллера?

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

Я хотел бы написать вспомогательную функцию rspec login для эмуляции входа в систему для тестов контроллера. (NB: я буду обрабатывать спецификации интеграции/запросов отдельно.) Мои попытки так и не сработали: метод logged_in? в ApplicationController возвращает false.

Вопрос: как мне написать хелпер входа в систему?

Вот тест контроллера RSpec:

# file: spec/controllers/searches_controller_spec.rb
require 'spec_helper'
require 'controllers_helper'
describe SearchesController do
  include ControllersHelper

  describe "GET index" do

    it 'without login renders login page' do
      get :index
      response.should redirect_to(login_path)
    end

    it 'with login finds searches belonging to user' do
      me = FactoryGirl.create(:user)
      my_searches = FactoryGirl.create_list(:search, 2, :user => me)
      not_me = FactoryGirl.create(:user)
      not_my_searches = FactoryGirl.create_list(:search, 2, :user => not_me)

      login(me)  # want to define this in spec/controllers_helper.rb
      get :index
      assigns(:searches).should =~ my_searches
    end
  end
end

Вот контроллер:

# file: app/controllers/searches_controller.rb
class SearchesController < ApplicationController

  def index
    unless logged_in?
      redirect_to login_path, :alert => "You must be logged in to access this page."
    else
      @searches = Search.where(:user_id => current_user.id)
      respond_to do |format|
        format.html
        format.json { render json: @searches }
      end
    end
  end

end

А вот и код ApplicationController. Обратите внимание, что current_user = x имеет эффект регистрации x, и это довольно просто: он устанавливает @current_user и session[:user_id].

# file: app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery
  force_ssl

  protected

  def current_user
    @current_user ||= User.find_by_id(session[:user_id])
  end

  def current_user=(user)
    @current_user = user
    session[:user_id] = user && user.id
  end

  def logged_in?
    !!@current_user
  end

  def require_login
    unless logged_in?
      redirect_to login_path, :alert => "You must be logged in to access this page."
    end
  end

  helper_method :current_user, :logged_in?, :require_login
end

person fearless_fool    schedule 18.09.2012    source источник


Ответы (1)


Возможно, я уже говорил это раньше, но если бы Stack Overflow давал значки, отвечающие на собственные вопросы, у меня было бы МНОГО значков! :)

Хорошо, чтобы ответить на этот вопрос, вам нужно посмотреть документацию для ActionController::TestCase. Когда вы это сделаете, вы обнаружите, что он устанавливает привязки для:

@controller
@request
@response

Таким образом, для конкретного контроллера, указанного в OP, написание метода login тривиально:

# file: spec/controllers_helper.rb
module ControllersHelper
  def login(user)
    @controller.send(:current_user=, user)
  end
end

(Я слышал, что кто-то снова сказал RTFM? Я так и думал...)

person fearless_fool    schedule 19.09.2012