요청 사양의 스터 빙 인증


84

요청 사양을 작성할 때 세션 및 / 또는 스텁 컨트롤러 메서드를 어떻게 설정합니까? 통합 테스트에서 인증 스텁을 시도하고 있습니다-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)>'

답변:


101

요청 사양은 ActionDispatch::IntegrationTest(을 감싸는 ActionController::TestCase) 컨트롤러 사양처럼 작동하지 않는 씬 래퍼 입니다. 사용 가능한 세션 메서드가 있지만 지원되지 않는다고 생각합니다 (즉, 다른 유틸리티에 포함되는 모듈에도 해당 메서드가 포함되어 있기 때문에있을 수 있습니다).

사용자 인증에 사용하는 모든 작업에 게시하여 로그인하는 것이 좋습니다. 모든 사용자 팩토리에 대해 암호를 'password'(예 :)로 지정하면 다음과 같이 할 수 있습니다.

def 로그인 (사용자)
  post login_path, : login => user.login, : password => 'password'
종료

1
감사합니다 David. 훌륭하게 작동하지만 모든 요청을 만드는 것이 약간 과잉 인 것 같습니까?
Jonas Nielsen

19
과잉이라고 생각했다면 추천하지 않았을 것입니다. :)
David Chelimsky 2011-04-27

6
또한 안정적으로 수행하는 가장 간단한 방법이기도합니다. ActionDispatch::IntegrationTest실제 브라우저를 사용하지 않고도 브라우저를 통해 상호 작용하는 한 명 이상의 사용자를 시뮬레이션하도록 설계되었습니다. 잠재적으로 하나 이상의 사용자 (예 : 세션)와 하나 이상의 컨트롤러가 단일 예제 내에 있으며 세션 / 컨트롤러 개체는 마지막 요청에 사용 된 것입니다. 요청 전에는 액세스 할 수 없습니다.
David Chelimsky

17
내가 사용해야하는 page.driver.post카피 바라와
이안 양

@IanYang page.driver.post은 반 패턴 일 수 있습니다. Capybara의 Jonas Nicklas 와 API 테스트 에 따르면 )
Epigene

61

Devise 사용자를위한 참고 사항 ...

BTW, @David Chelimsky의 답변은 Devise를 사용하는 경우 약간의 조정이 필요할 수 있습니다 . 통합 / 요청 테스트에서 내가하는 일 ( 이 StackOverflow 게시물 덕분에 ) :

# file: spec/requests_helper.rb
def login(user)
  post_via_redirect user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
end

2
그런 다음 rspec 모델 사양에서 'login user1'을 사용할 때 # <RSpec :: Core :
jpw

1
이것은 당신이 가정 devise_for :users에서 config/routes.rb파일. 다른 것을 지정한 경우 그에 따라 코드를 조정해야합니다.
fearless_fool

이것은 나를 위해 일했습니다. 약간 수정해야했습니다. 내 앱이 이메일 대신 로그인으로 사용자 이름을 사용 'user[email]' => user.email하기 'user[username]' => user.username때문에로 변경 했습니다 .
webdevguy

3

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

편집 : 고정 오타


-1

세션을 아주 쉽게 스텁 할 수 있습니다.

controller.session.stub(:[]).with(:user_id).and_return(<whatever user ID>)

모든 루비 특수 연산자는 실제로 메서드입니다. 호출은와 1+1동일 합니다. 1.+(1)+, 메서드 일뿐입니다. 마찬가지로, session[:user_id]메소드를 호출하는 것과 동일 []session으로,session.[](:user_id)


이것은 합리적인 해결책처럼 보입니다.
superluminary 2014 년

2
이것은 요청 사양에서는 작동하지 않지만 컨트롤러 사양에서만 작동합니다.
Machisuji

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.