RSpec与Cookies – 即使应用程序正常工作(模拟已登录的用户),测试也会失败

我正在阅读Michael Hartl的“Ruby on Rails”Turorial“但我被困在这里。

我写了测试以检查用户编辑/更新的用户授权,我还编写了控制器代码, 它的工作原理如下:

  1. 如果用户未登录并尝试访问users#editusers#update则会将其重定向到登录页面
  2. 如果用户已登录并且他尝试编辑另一个用户,则会将其重定向到根目录

问题是在测试第2点的规范中,我检查发送PUT请求到user_path我被重定向到root但运行rspec我得到以下错误:

 Failures: 1) Authentication authorization as wrong user submitting a PUT request to users#update Failure/Error: specify { response.should redirect_to(root_url) } Expected response to be a redirect to  but was a redirect to  # ./spec/requests/authentication_pages_spec.rb:73:in `block (5 levels) in ' 

它似乎被重定向到signin_url而不是root_url ,就像用户根本没有登录一样……这就是我猜测导致问题的原因。

应用程序在cookie中存储令牌以对用户进行身份validation。 为了测试这个,我编写了一个名为signin_user(user)的辅助方法,并将其放在spec/support/utilities.rb文件中:

 # spec/support/utilities.rb def sign_in(user) visit signin_path fill_in "Email", with: user.email fill_in "Password", with: user.password click_button "Sign in" # Make signin work even when not using capybara (eg when using get, or post) cookies[:remember_token] = user.remember_token end 

正如您所看到的那样,设置remember_token cookie以确保用户即使在使用putdelete等时也会被记录…或者至少它应该工作!

我怎样才能使这个规格通过呢?

 # spec/requests/authentication_pages_spec.rb require 'spec_helper' describe "Authentication" do subject { page } # ... describe "authorization" do # ... describe "as wrong user" do let(:user) { FactoryGirl.create(:user) } let(:another_user) { FactoryGirl.create(:user, email: "another@example.com") } before { sign_in(user) } # ... describe "submitting a PUT request to users#update" do before { put user_path(another_user) } specify { response.should redirect_to(root_url) } end end end end 

更新 :这是我的UsersController

 class UsersController  [:edit, :update] before_filter :correct_user, :only => [:edit, :update] def show @user = User.find(params[:id]) end def new @user = User.new end def create @user = User.new(params[:user]) if @user.save sign_in @user flash[:success] = "Welcome to the sample App!" redirect_to @user else render "new" end end def edit end def update if @user.update_attributes(params[:user]) sign_in(@user) flash[:success] = "Your profile was successfully updated" redirect_to @user else render "edit" end end private def signed_in_user unless signed_in? redirect_to signin_url, notice: "Please sign in to access this page." end end def correct_user @user = User.find(params[:id]) redirect_to root_url unless current_user?(@user) end end 

在查看github存储库中其余代码的帮助程序后,我认为我发现了问题。

您正在使用session变量来存储:remember_token

  def user_from_remember_token remember_token = session[:remember_token] User.find_by_remember_token(remember_token) unless remember_token.nil? end 

这本书使用cookies:

  def user_from_remember_token remember_token = cookies[:remember_token] User.find_by_remember_token(remember_token) unless remember_token.nil? end 

您的测试助手设置了cookie:

 # Make signin work even when not using capybara (eg when using get, or post) cookies[:remember_token] = user.remember_token 

但是因为你的user_from_remember_token正在寻找session[:remember_token]而不是cookie,它认为用户没有登录,因此测试被重定向到login_path而不是root_path

它说明了为什么他们在这里使用cookie: http : //ruby.railstutorial.org/chapters/sign-in-sign-out? version = 3.2#sec: a_working_sign_in_method


如果您想继续使用会话,则需要调整测试以通过post登录,以便put具有会话集,例如:

  describe "submitting a PUT request to users#update" do before do post sessions_path, :email => user.email, :password => user.password put user_path(another_user) end specify { response.should redirect_to(root_url) } end 

谢谢你的回答! 我也正在完成这本书并遇到同样的问题。 使用会话的原因是第8.5节中的练习2是使用会话而不是cookie。

我的回答有点不同。 我的SessionsController在params中使用会话变量:

  def create user = User.find_by_email(params[:session][:email]) if user && user.authenticate(params[:session][:password]) sign_in user redirect_back_or user else flash.now[:error] = 'Invalid email/password combination' render 'new' end end 

所以修复稍微复杂一点:

 #spec/support/utilities.rb def sign_in(user) visit signin_path fill_in "session_email", with: user.email fill_in "session_password", with: user.password click_button "Sign in" # Sign in when not using Capybara as well. post sessions_path, {:session => { :email => user.email, :password => user.password }} end 

我有同样的问题,但原因不同。

我在spec / support / utilities.rb中输了一个错字

 def sign_in(user) visit signin_path fill_in "Email", with: user.email fill_in "Password", with: user.password click_button "Sign in" # Sign in when not using Capybara as well cookies[:remember_toke] = user.remember_token end 

请注意,最后一行显示“:remember_toke”而不是“:remember_token”

不知何故,导致测试失败并重定向到登录。

所以我在这里记录这个,以防其他人犯同样的错误。