2011-04-26 3 views
76

요청 사양을 작성할 때 세션 및/또는 스텁 컨트롤러 메서드를 어떻게 설정합니까? 나는 내 통합 테스트에서 인증을 스텁하기 위해 노력하고있어 - RSpec에/여기요청 사양의 스텁 인증

를 요청하는 테스트의 예

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)>' 

답변

97

요구 사양 제어기 사양처럼 작동하지 않는 얇은 랩퍼 주변 ActionDispatch::IntegrationTest이다 (이 랩 ActionController::TestCase). 사용할 수있는 세션 방법이 있지만 지원되지 않는다고 생각합니다 (즉, 다른 유틸리티에 포함 된 모듈에 해당 방법이 포함되어있을 가능성이 높습니다).

사용자를 인증하는 데 사용하는 모든 작업에 게시하여 로그인하는 것이 좋습니다. 모든 사용자 공장의 암호 (예를 들어) '비밀번호'를 한 경우에, 당신은 같은 것을 할 수 있습니다 : 당신이 고안를 사용하는 경우

 
def login(user) 
    post login_path, :login => user.login, :password => 'password' 
end 
+0

감사 데이빗. 그것은 훌륭하게 작동하지만, 모든 요청을하는 것은 조금 과잉스러운 것 같습니다. –

+17

과도함이라고 생각하면 추천하지 않았을 것입니다. –

+4

신뢰할 수있는 가장 간단한 방법입니다. 'ActionDispatch :: IntegrationTest'는 실제 브라우저를 사용하지 않고도 브라우저를 통해 상호 작용하는 한 명 이상의 사용자를 시뮬레이트하도록 설계되었습니다. 잠재적으로 둘 이상의 사용자가 있습니다 (예 :세션) 및 한 개 이상의 컨트롤러를 포함하며, 세션/컨트롤러 개체는 마지막 요청에서 사용 된 개체입니다. 요청하기 전에 액세스 할 권한이 없습니다. –

58

BTW, @ 데이비드 Chelimsky의 대답은 약간의 조정이 필요할 수 있습니다 . 나는 (this StackOverflow post 덕분에) 내 통합/요청 테스트에서 뭘하는지 :

# 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'을 사용할 때 정의되지 않은 지역 변수 또는 메소드 'user_session_path'가 # 가됩니다. – jpwynn

+1

이것은 'config/routes.rb' 파일에'devise_for : users'가 있습니다. 다른 것을 지정했다면 그에 따라 코드를 수정해야합니다. –

+0

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

2

FWIW, 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, "https://stackoverflow.com/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.[](:user_id)

+0

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

+1

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