При написании спецификации запроса, как вы устанавливаете сеансы и / или методы контроллера заглушки? Я пытаюсь отключить аутентификацию в своих интеграционных тестах - rspec / requests
Вот пример теста
require File.dirname(__FILE__) + '/../spec_helper'
require File.dirname(__FILE__) + '/authentication_helpers'
describe "Messages" do
include AuthenticationHelpers
describe "GET admin/messages" do
before(:each) do
@current_user = Factory :super_admin
login(@current_user)
end
it "displays received messages" do
sender = Factory :jonas
direct_message = Message.new(:sender_id => sender.id, :subject => "Message system.", :content => "content", :receiver_ids => [@current_user.id])
direct_message.save
get admin_messages_path
response.body.should include(direct_message.subject)
end
end
end
Помощник:
module AuthenticationHelpers
def login(user)
session[:user_id] = user.id # session is nil
#controller.stub!(:current_user).and_return(user) # controller is nil
end
end
И ApplicationController, который обрабатывает аутентификацию:
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user
helper_method :logged_in?
protected
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def logged_in?
!current_user.nil?
end
end
Почему нет доступа к этим ресурсам?
1) Messages GET admin/messages displays received messages
Failure/Error: login(@current_user)
NoMethodError:
undefined method `session' for nil:NilClass
# ./spec/requests/authentication_helpers.rb:3:in `login'
# ./spec/requests/message_spec.rb:15:in `block (3 levels) in <top (required)>'
источник
ActionDispatch::IntegrationTest
предназначен для имитации взаимодействия одного или нескольких пользователей через браузеры без необходимости использования реальных браузеров. В одном примере потенциально может быть более одного пользователя (т.е. сеанса) и более одного контроллера, а объекты сеанса / контроллера - это те, которые использовались в последнем запросе. У вас нет доступа к ним до запроса.page.driver.post
с Capybarapage.driver.post
может быть антипаттерном, согласно Джонасу Никласу в Capybara and testing APIs )Примечание для пользователей Devise ...
Кстати, ответ @David Chelimsky может потребовать небольшой настройки, если вы используете Devise . Что я делаю при тестировании интеграции / запросов (благодаря этому сообщению на StackOverflow ):
# file: spec/requests_helper.rb # Rails 6 def login(user) post user_session_path, params: { user: { email: user.email, password: user.password } } follow_redirect! end # Rails 5 or older def login(user) post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password end
источник
devise_for :users
вconfig/routes.rb
файле. Если вы указали что-то другое, вам придется соответствующим образом настроить свой код.'user[email]' => user.email
на,'user[username]' => user.username
поскольку мое приложение использует имя пользователя в качестве логина вместо электронной почты.FWIW, при переносе моих тестов Test :: Unit на RSpec, я хотел иметь возможность входить в систему с несколькими (разрабатывать) сеансами в моих спецификациях запросов. Потребовалось немного покопаться, но это сработало для меня. Использование Rails 3.2.13 и RSpec 2.13.0.
# file: spec/support/devise.rb module RequestHelpers def login(user) ActionController::IntegrationTest.new(self).open_session do |sess| u = users(user) sess.post '/users/sign_in', { user: { email: u.email, password: 'password' } } sess.flash[:alert].should be_nil sess.flash[:notice].should == 'Signed in successfully.' sess.response.code.should == '302' end end end include RequestHelpers
И...
# spec/request/user_flows.rb require 'spec_helper' describe 'User flows' do fixtures :users it 'lets a user do stuff to another user' do karl = login :karl karl.get '/users' karl.response.code.should eq '200' karl.xhr :put, "/users/#{users(:bob).id}", id: users(:bob).id, "#{users(:bob).id}-is-funny" => 'true' karl.response.code.should eq '200' User.find(users(:bob).id).should be_funny bob = login :bob expect { bob.get '/users' }.to_not raise_exception bob.response.code.should eq '200' end end
Изменить : исправлена опечатка
источник
Вы также можете довольно легко прервать сеанс.
controller.session.stub(:[]).with(:user_id).and_return(<whatever user ID>)
Все специальные операторы ruby действительно являются методами. Вызов
1+1
аналогичен вызову1.+(1)
, что означает, что+
это просто метод. Аналогично,session[:user_id]
это то же самое, что и вызов метода[]
onsession
, посколькуsession.[](:user_id)
источник
Я нашел это очень полезным для Devise: https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)
источник