如何使用RSpec模拟登录?

bra*_*rad 49 rspec ruby-on-rails factory-bot

我已经玩Rails几年了,并且已经制作了一些正在制作的可通过的应用程序.我总是避免做任何测试,但我决定纠正这个问题.我正在尝试为我已经开始运行但正在不断修改的工作编写的应用程序编写一些测试.我担心任何改变都会破坏事情,所以我想让一些测试运行起来.我已经阅读了RSpec的书,观看了一些截屏视频,但我正在努力开始(这让我觉得你做的事情只有在你实际完成之后才明白).

我正在尝试编写应该是我的ReportsController的简单测试.我的应用程序的问题在于,整个事情几乎都位于身份验证层之后.如果你没有登录就没有任何作用所以我必须先模拟一个登录才能发出一个简单的get请求(虽然我想我应该写一些测试来确保没有登录就没有任何作用 - 我会去以后).

我已经建立了一个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
Run Code Online (Sandbox Code Playgroud)

然后像这样写我的测试;

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
Run Code Online (Sandbox Code Playgroud)

这样就失败了;

  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)>'
Run Code Online (Sandbox Code Playgroud)

有趣的是,如果我将测试更改为response.should be_redirect,测试通过,这表明一切正常,直到该点,但登录未被识别.

所以我的问题是我需要做些什么来使这个登录工作.我是否需要在数据库中创建与FactoryGirl凭据匹配的用户?如果是这样,FactoryGirl在这里有什么意义(我应该使用它吗?)如何在测试环境中创建这个假用户?我的身份验证系统是一个非常简单的自制系统(基于Railscasts第250集).这种登录行为可能必须复制几乎所有的测试,所以如何在我的代码中执行一次并将其应用到所有地方?

我意识到这是一个很大的问题,所以我感谢你一看.

Bra*_*dan 45

答案取决于您的身份验证实现.通常,当用户登录时,您将设置会话变量以记住该用户,例如session[:user_id].before_filter如果不存在此类会话变量,您的控制器将检查a中的登录和重定向.我假设你已经在做这样的事了.

要使测试工作正常,您必须手动将用户信息插入到会话中.这是我们在工作中使用的部分内容:

# 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
Run Code Online (Sandbox Code Playgroud)

现在,在我们的任何控制器示例中,我们都可以调用login(some_user)模拟以该用户身份登录.


我还应该提一下,看起来你在这个控制器测试中正在进行集成测试.通常,您的控制器测试应该只模拟对各个控制器操作的请求,例如:

it 'should be successful' do
  get :index
  response.should be_success
end
Run Code Online (Sandbox Code Playgroud)

这专门测试单个控制器操作,这是您在一组控制器测试中所需的操作.然后,您可以使用Capybara/Cucumber进行表单,视图和控制器的端到端集成测试.


Tai*_*aiz 8

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
Run Code Online (Sandbox Code Playgroud)

现在在spec/rails_helper.rbspec/spec_helper.rb 文件中添加以下行

require 'support/controller_helpers'

RSpec.configure do |config|

    config.include Devise::TestHelpers, :type => :controller
    config.include ControllerHelpers, :type => :controller

  end
Run Code Online (Sandbox Code Playgroud)

现在在你的控制器spec文件中.

describe  "GET #index" do

    before :each do        
        @user=create(:user)
        sign_in @user
    end
      ...
end
Run Code Online (Sandbox Code Playgroud)

设计官方链接

  • 该问题与设计无关 (2认同)