Ruby on rails 如何使用RSpec模拟登录?
我已经玩Rails好几年了,并且已经开发出了几款在生产中还可以使用的应用程序。我一直避免做任何测试,但我已经决定纠正这一点。我正在尝试为一个应用程序编写一些测试,这个应用程序是我为已经启动并运行但正在不断修改的工作编写的。我担心任何更改都会破坏一切,所以我想启动并运行一些测试。我读过RSpec的书,看了一些屏幕广播,但我很难开始(我觉得这是一种只有在你真正做了之后才能理解的事情) 我正在尝试编写一个简单的ReportsController测试。我的应用程序的问题是,几乎所有的东西都位于身份验证层之后。如果您未登录,则无法正常工作,因此我必须先模拟登录,然后才能发送一个简单的get请求(尽管我想我应该编写一些测试,以确保在没有登录的情况下无法正常工作-稍后我将进行讨论) 我已经用RSpec、Capybara、FactoryGirl和Guard建立了一个测试环境(不确定使用哪种工具,所以使用了Railscasts的建议)。到目前为止,我编写测试的方式是在FactoryGirl中创建这样一个用户Ruby on rails 如何使用RSpec模拟登录?,ruby-on-rails,rspec,factory-bot,Ruby On Rails,Rspec,Factory Bot,我已经玩Rails好几年了,并且已经开发出了几款在生产中还可以使用的应用程序。我一直避免做任何测试,但我已经决定纠正这一点。我正在尝试为一个应用程序编写一些测试,这个应用程序是我为已经启动并运行但正在不断修改的工作编写的。我担心任何更改都会破坏一切,所以我想启动并运行一些测试。我读过RSpec的书,看了一些屏幕广播,但我很难开始(我觉得这是一种只有在你真正做了之后才能理解的事情) 我正在尝试编写一个简单的ReportsController测试。我的应用程序的问题是,几乎所有的东西都位于身份验证层
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.rb或spec/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