Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何使用RSpec模拟登录?_Ruby On Rails_Rspec_Factory Bot - Fatal编程技术网

Ruby on rails 如何使用RSpec模拟登录?

Ruby on rails 如何使用RSpec模拟登录?,ruby-on-rails,rspec,factory-bot,Ruby On Rails,Rspec,Factory Bot,我已经玩Rails好几年了,并且已经开发出了几款在生产中还可以使用的应用程序。我一直避免做任何测试,但我已经决定纠正这一点。我正在尝试为一个应用程序编写一些测试,这个应用程序是我为已经启动并运行但正在不断修改的工作编写的。我担心任何更改都会破坏一切,所以我想启动并运行一些测试。我读过RSpec的书,看了一些屏幕广播,但我很难开始(我觉得这是一种只有在你真正做了之后才能理解的事情) 我正在尝试编写一个简单的ReportsController测试。我的应用程序的问题是,几乎所有的东西都位于身份验证层

我已经玩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
然后像这样写我的测试

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
这样失败了

  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)>'
1)ReportsController获取“索引”应成功
失败/错误:response.should\u success
预期的成功?返回真,得到假
#./spec/controllers/reports\u controller\u spec.rb:13:in'block(3层)in'
有趣的是,如果我将我的测试更改为
response.should\u redirect
,测试通过,这向我表明,在这一点之前,一切都在运行,但登录未被识别

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


我意识到这是一个大问题,所以我感谢你的关注

答案取决于您的身份验证实现。通常,当用户登录时,您将设置一个会话变量来记住该用户,类似于
session[:user\u id]
。您的控制器将在_filter之前在
中检查登录,如果不存在此类会话变量,则重定向。我想你已经在做类似的事情了

要在测试中实现这一点,必须手动将用户信息插入会话。以下是我们在工作中使用的部分内容:

# 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
现在,在我们的任何控制器示例中,我们都可以调用
login(some_user)
来模拟作为该用户登录


我还应该提到,在这个控制器测试中,看起来您正在进行集成测试。通常,控制器测试应仅模拟对单个控制器操作的请求,如:

it 'should be successful' do
  get :index
  response.should be_success
end

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

因为我无法让@Brandan的答案起作用,但基于此,我得出了以下解决方案:

# spec/support/rails_helper.rb
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } # Add this at top of file

...

include ControllerMacros # Add at bottom of file

然后在测试中,您可以使用:

it "works" do
  login_as(FactoryGirl.create(:user))
  expect(request.session[:user_id]).not_to be_nil
end

在spec/support/controller\u 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
现在在spec/rails\u helper.rbspec/spec\u helper.rb 文件

现在在控制器规范文件中

describe  "GET #index" do

    before :each do        
        @user=create(:user)
        sign_in @user
    end
      ...
end

在功能测试中与用户一起登录的最简单方法是使用管理员的


对于不使用Desive的用户:

spec/rails\u helper.rb

需要相对的“支持/登录帮助”
RSpec.configure do | config|
config.include登录密码
结束
spec/support/login\u helpers.rb

模块登录器
def登录身份(用户)
post“/session”,参数:{session:{email:user.email,密码:“password”}
结束
结束
在规格中:

login\u as(用户)

太好了,谢谢。这是朝着正确方向的巨大推动。我已经将其付诸实践,但仍然有一个失败的测试,因为我没有在测试环境中设置任何用户。我应该如何设置它们?使用工厂女孩?使用测试环境在控制台中创建它们?跨现有生产数据库复制到测试环境?实际上,不用担心。我设法和工厂女工这样做了<代码>描述“获取‘索引’”do;它“应该成功”吗;user=FactoryGirl.create(:user);登录(用户);get:索引;回应。应该是成功;结束;结束。我不得不将
request.session[:user]
更改为
request.session[:user\u id]
,但除此之外,您代码中的所有内容都对我有效,我现在有了第一次通过测试!谢谢。是的,您使用FactoryGirl创建用户的解决方案本质上也是我们所做的。如果答案对你有效,请务必接受。谢谢@Brandan在控制器规范中使用FactoryGirl访问数据库也使其成为集成测试,不是吗?我不知道你的答案为什么得到
-1
,因为这是唯一一个对我有效的答案,即使它看起来有点“凌乱”;非常感谢,伙计;)首先,
未定义的方法创建
。如果此人应该将
创建
更改为其他内容,那么为什么不提及它呢?我是否应该将
描述
登录
替换为其他内容?这个伪代码令人困惑。问题是
require 'support/controller_helpers'

RSpec.configure do |config|

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

  end
describe  "GET #index" do

    before :each do        
        @user=create(:user)
        sign_in @user
    end
      ...
end
login_as some_user