Подтвердить что ты не робот

Как смоделировать логин с RSpec?

Я играю с Rails уже пару лет и выпустил пару пассивных приложений, которые находятся в производстве. Однако я всегда избегал делать какие-либо тесты, и я решил исправить это. Я пытаюсь написать несколько тестов для приложения, которое я написал для работы, которая уже запущена и работает, но подвергается постоянной ревизии. Я обеспокоен тем, что любые изменения нарушат ситуацию, поэтому я хочу запустить и запустить некоторые тесты. Я прочитал книгу RSpec, посмотрел несколько скринкастов, но изо всех сил стараюсь начать (это поражает меня, как вид, который вы понимаете только после того, как вы это сделали).

Я пытаюсь написать, что должно быть простым тестом моего ReportController. Проблема с моим приложением заключается в том, что в значительной степени все зависит от уровня аутентификации. Ничего не работает, если вы не вошли в систему, поэтому мне нужно смоделировать логин, прежде чем я могу даже отправить простой запрос на получение (хотя, я думаю, я должен написать несколько тестов, чтобы убедиться, что ничего не работает без входа в систему - я доберусь до это позже).

Я установил тестовую среду с RSpec, Capybara, FactoryGirl и Guard (не был уверен, какие инструменты используют так используемые предложения Railscasts). То, как я уже писал о своем тестировании, заключается в том, чтобы создать пользователя в FactoryGirl, например:

FactoryGirl.define do
  sequence(:email) {|n| "user#{n}@example.com"}
  sequence(:login) {|n| "user#{n}"}
  factory :user do
    email {FactoryGirl.generate :email}
    login {FactoryGirl.generate :login}
    password "abc"
    admin false
    first_name "Bob"
    last_name "Bobson"
  end
end

а затем напишите мой тест следующим образом:

require 'spec_helper'

describe ReportsController do
  describe "GET 'index'" do
    it "should be successful" do
      user = Factory(:user)
      visit login_path
      fill_in "login", :with => user.login
      fill_in "password", :with => user.password
      click_button "Log in"
      get 'index'
      response.should be_success
    end
  end
end

Это не так:

  1) ReportsController GET 'index' should be successful
     Failure/Error: response.should be_success
       expected success? to return true, got false
     # ./spec/controllers/reports_controller_spec.rb:13:in `block (3 levels) in <top (required)>'

Интересно, если я изменил свой тест на response.should be_redirect, тестовый проход подскажет мне, что все работает до этой точки, но логин не распознается.

Итак, мой вопрос заключается в том, что мне нужно сделать, чтобы сделать эту работу. Мне нужно создать пользователя в базе данных, которая соответствует учетным данным FactoryGirl? Если да, то в чем смысл FactoryGirl здесь (и должен ли я его использовать)? Как мне создать этот поддельный пользователь в тестовой среде? Моя система аутентификации - очень простая самодельная (основанная на

4b9b3361

Ответ 1

Ответ зависит от вашей реализации аутентификации. Обычно, когда пользователь входит в систему, вы должны установить переменную сеанса, чтобы запомнить этого пользователя, что-то вроде session[:user_id]. Ваши контроллеры будут проверять вход в систему before_filter и перенаправлять, если такая переменная сеанса отсутствует. Я предполагаю, что вы уже делаете что-то вроде этого.

Чтобы это работало в ваших тестах, вам необходимо вручную вставить информацию о пользователе в сеанс. Здесь часть того, что мы используем на работе:

# spec/support/spec_test_helper.rb
module SpecTestHelper   
  def login_admin
    login(:admin)
  end

  def login(user)
    user = User.where(:login => user.to_s).first if user.is_a?(Symbol)
    request.session[:user] = user.id
  end

  def current_user
    User.find(request.session[:user])
  end
end

# spec/spec_helper.rb
RSpec.configure do |config|
  config.include SpecTestHelper, :type => :controller
end

Теперь в любом из наших примеров контроллеров мы можем вызвать login(some_user) для имитации входа в систему как этого пользователя.


Я должен также упомянуть, что похоже, что вы проводите тестирование интеграции в этом тесте контроллера. Как правило, ваши тесты контроллера должны только имитировать запросы отдельных действий контроллера, например:

it 'should be successful' do
  get :index
  response.should be_success
end

Это специально проверяет действие одного контроллера, что вам нужно в наборе тестов контроллера. Затем вы можете использовать Capybara/Cucumber для комплексного тестирования интеграции форм, представлений и контроллеров.

Ответ 2

Добавить вспомогательный файл в spec/support/controller_helpers.rb и скопировать содержимое ниже

module ControllerHelpers
    def sign_in(user)
      if user.nil?
        allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user})
        allow(controller).to receive(:current_user).and_return(nil)
      else
        allow(request.env['warden']).to receive(:authenticate!).and_return(user)
        allow(controller).to receive(:current_user).and_return(user)
      end
    end
  end

Теперь добавьте следующие строки в spec/rails_helper.rb или spec/spec_helper.rb  файл

require 'support/controller_helpers'

RSpec.configure do |config|

    config.include Devise::TestHelpers, :type => :controller
    config.include ControllerHelpers, :type => :controller

  end

Теперь в вашем файле спецификации контроллера.

describe  "GET #index" do

    before :each do        
        @user=create(:user)
        sign_in @user
    end
      ...
end

Разработать официальную ссылку

Ответ 3

Поскольку я не мог заставить @Brandan отвечать на работу, но на основе этого и этот пост, я пришел к этому решению:

# spec/support/rails_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } # Add this at top of file

...

include ControllerMacros # Add at bottom of file

и

# spec/support/controller_macros.rb
module ControllerMacros

  def login_as_admin
    admin = FactoryGirl.create(:user_admin)
    login_as(admin)
  end

  def login_as(user)
    request.session[:user_id] = user.id
  end

end

Затем в ваших тестах вы можете использовать:

it "works" do
  login_as(FactoryGirl.create(:user))
  expect(request.session[:user_id]).not_to be_nil
end

Ответ 4

Самый простой способ войти в систему с пользователем при тестировании функций - использовать Warden helper #login_as

login_as some_user