Как смоделировать логин с 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 здесь (и должен ли я его использовать)? Как мне создать этот поддельный пользователь в тестовой среде? Моя система аутентификации - очень простая самодельная (основанная на
Ответы
Ответ 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