Cố gắng xác thực trong thông số yêu cầu


84

Khi viết một đặc tả yêu cầu, làm cách nào để bạn thiết lập các phiên và / hoặc các phương thức điều khiển sơ khai? Tôi đang cố gắng xác thực trong các bài kiểm tra tích hợp của mình - rspec / Request

Đây là một ví dụ về bài kiểm tra

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

Người trợ giúp:

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

Và ApplicationController xử lý xác thực:

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

Tại sao không thể truy cập các tài nguyên này?

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

Câu trả lời:


101

Thông số yêu cầu là một lớp bọc mỏng xung quanh ActionDispatch::IntegrationTest, không hoạt động giống như thông số kỹ thuật của bộ điều khiển (cái bọc ActionController::TestCase). Mặc dù có một phương thức phiên có sẵn, tôi không nghĩ rằng nó được hỗ trợ (nghĩa là nó có thể ở đó vì một mô-đun được bao gồm cho các tiện ích khác cũng bao gồm phương thức đó).

Tôi khuyên bạn nên đăng nhập bằng cách đăng bất kỳ hành động nào bạn sử dụng để xác thực người dùng. Nếu bạn đặt mật khẩu 'password' (ví dụ) cho tất cả các nhà máy Người dùng, thì bạn có thể làm như sau:

đăng nhập def (người dùng)
  đăng login_path,: login => user.login,: password => 'password'
kết thúc

1
Cảm ơn David. Nó hoạt động tốt, nhưng nó có vẻ hơi quá mức cần thiết khi thực hiện tất cả những yêu cầu đó?
Jonas Nielsen

19
Nếu tôi nghĩ rằng nó là quá mức cần thiết, tôi sẽ không có khuyến cáo nó :)
David Chelimsky

6
Đây cũng là cách đơn giản nhất để làm điều đó một cách đáng tin cậy. ActionDispatch::IntegrationTestđược thiết kế để mô phỏng một hoặc nhiều người dùng tương tác qua trình duyệt mà không cần phải sử dụng trình duyệt thực. Có thể có nhiều người dùng (tức là phiên) và nhiều hơn một bộ điều khiển trong một ví dụ duy nhất và các đối tượng phiên / bộ điều khiển là những đối tượng được sử dụng trong yêu cầu cuối cùng. Bạn không có quyền truy cập vào chúng trước khi có yêu cầu.
David Chelimsky

17
Tôi phải sử dụng page.driver.postvới Capybara
Ian Yang

@IanYang page.driver.postcó thể là một antipattern, theo Jonas Nicklas trong Capybara và API thử nghiệm )
Epigene

61

Lưu ý cho người dùng Devise ...

BTW, câu trả lời của @David Chelimsky có thể cần chỉnh sửa một chút nếu bạn đang sử dụng Devise . Những gì tôi đang làm trong quá trình kiểm tra tích hợp / yêu cầu của mình (nhờ bài đăng StackOverflow này ):

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

2
khi tôi sau đó sử dụng 'đăng nhập user1' trong một mô hình đặc tả rspec, tôi nhận được undefined biến hoặc phương pháp 'user_session_path' địa phương cho # <RSpec :: Core:
jpw

1
Điều này giả sử bạn có devise_for :userstrong config/routes.rbhồ sơ. Nếu bạn đã chỉ định một cái gì đó khác, bạn sẽ phải điều chỉnh mã của mình cho phù hợp.
Fearless_fool

Điều này làm việc cho tôi vì tôi đã phải sửa đổi nó một chút. Tôi đã thay đổi 'user[email]' => user.emailthành 'user[username]' => user.usernamevì ứng dụng của tôi sử dụng tên người dùng làm thông tin đăng nhập thay vì email.
webdevguy

3

FWIW, khi chuyển Bài kiểm tra :: Đơn vị của tôi sang RSpec, tôi muốn có thể đăng nhập với nhiều phiên (devise) trong thông số kỹ thuật yêu cầu của mình. Phải mất một số công đoạn đào, nhưng tôi đã nhận được điều này. Sử dụng Rails 3.2.13 và 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

Và ...

# 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

Chỉnh sửa : sửa lỗi đánh máy


-1

Bạn cũng có thể dễ dàng khai mạc phiên họp.

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

Tất cả các toán tử đặc biệt của ruby ​​thực sự là các phương thức. Gọi 1+1là giống như 1.+(1), có nghĩa +là chỉ là một phương pháp. Tương tự, session[:user_id]cũng giống như phương thức gọi []trên session, nhưsession.[](:user_id)


Đây có vẻ là một giải pháp hợp lý.
siêu thường

2
Điều này không hoạt động trong thông số kỹ thuật yêu cầu, mà chỉ hoạt động trong thông số kỹ thuật bộ điều khiển.
Machisuji

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.