在michael hart'l教程测试中无法理解no_capybara选项

时间:2013-09-04 18:00:42

标签: ruby-on-rails rspec capybara

在michael hart'l的rails教程中,我无法理解规范:

require 'spec_helper'

describe "Authentication" do
  .
  .
  .
  describe "authorization" do
    .
    .
    .
    describe "as wrong user" do
     let(:user) { FactoryGirl.create(:user) }
     let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
     before { sign_in user, no_capybara: true }

     describe "visiting Users#edit page" do
        before { visit edit_user_path(wrong_user) }
        it { should_not have_title(full_title('Edit user')) }
     end

     describe "submitting a PATCH request to the Users#update action" do
        before { patch user_path(wrong_user) }
        specify { expect(response).to redirect_to(root_url) }
     end
   end
  end
end 

如您所见,作者在每个示例之前使用before { sign_in user, no_capybara: true }登录用户。 no_capybara选项声明为:

规格/支持/ utilities.rb

.
. 
.
def sign_in(user, options={})
  if options[:no_capybara]
    # Sign in when not using Capybara.
    remember_token = User.new_remember_token
    cookies[:remember_token] = remember_token
    user.update_attribute(:remember_token, User.encrypt(remember_token))
  else
   visit signin_path
   fill_in "Email",    with: user.email
   fill_in "Password", with: user.password
   click_button "Sign in"
  end
end
正如他在教程中指出的那样:当直接使用其中一种HTTP请求方法(get,post,patch或delete)时,这是必要的(他的意思是no_capybara选项),我可以理解为“向用户提交PATCH请求#news操作“正在使用补丁方法,但上面的sign_in方法与此行(补丁方法)之间的关系是什么,在我的理解我认为 sign_in 使用 使用补丁,所以为什么我们应该添加 no_capybara

这个选项>

5 个答案:

答案 0 :(得分:2)

我对同一部分的测试失败了这些消息:

Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/signin>.

对你来说是一样的吗?网址为“http://www.example.com/”对您来说不奇怪吗?我们在应用程序的任何位置都没有使用此URL。那是Capybara这样做的。这意味着,正如所有其他人所说的那样,Capybara实际上并没有在我们的实际应用程序中创建cookie,它只是在模拟登录。我们将不得不在Capybara的文档中进行更多搜索,以便在这一点上准确理解它是如何工作的。但是你看到Capybara没有进行实际登录。现在,如果你看到我们的users_controller.rb

before_action :signed_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]

反过来,做:

def signed_in_user
  redirect_to signin_url, notice: "Please sign in." unless signed_in?
end

def correct_user
  @user = User.find(params[:id])
  redirect_to(root_url) unless current_user?(@user)
end

因此,当测试要求:

before { get edit_user_path(wrong_user) }

它会被控制器自动重定向到signin_url,因为正如我之前所说,用户并没有真正登录,没有为他设置任何cookie。这就是为什么必须提前设置cookie。

答案 1 :(得分:0)

看起来他只是想制作一个更快/更少依赖的测试套件。当您使用Capybara驱动程序完成登录过程时,最终结果是您在浏览器中放置了一个cookie,这是请求之间用户会话的持续时间。

通过提供“no_capybara”选项,您可以避免呈现登录页面,查找并填写所有信息,提交页面,然后在登录后重定向到第一页。你想要的只是浏览器中的cookie,所以他只是直接设置它并跳过其他所有内容。

答案 2 :(得分:0)

no_capybara是必需的,因为水豚不能直接提交'补丁'或'放'HTTP方法。

请参阅:Why Capybara can't submit directly to put action?

由于水豚无法提交投放/补丁,我们需要手动进行更改,这就是为什么Micheal使用:no_capybara选项来识别这种情况。

答案 3 :(得分:0)

我遇到了同样的问题,我无法理解为什么在使用直接HTTP请求时应该使用其他类型的登录。

我再次阅读了Michael Hartl教程的一些部分,原因似乎是cookies对象在测试中的工作方式不同,因为它只是一个模拟。因此,对于直接的http请求,您不能只填写表单并使用“常规”sign_in。您必须使用:no_capybara选项将remember_token直接设置为cookie。

我希望作者的评论有所帮助:

  

如注释行中所述,填写表单在不使用Capybara时不起作用,因此为了涵盖这种情况,我们允许用户传递选项no_capyabara:true以覆盖默认的signin方法并直接操作cookie 。当直接使用其中一个HTTP请求方法(get,post,patch或delete)时,这是必要的,如代码清单9.45所示。 (请注意,测试cookie对象不是真正的cookie对象的完美模拟;特别是,代码清单8.19中所见的cookies.permanent方法在测试中不起作用。)正如您可能怀疑的那样,sign_in方法将证明是有用的在未来的测试中,事实上它已经可以用来消除一些重复(第9.6节)。

答案 4 :(得分:0)

这可能为时已晚,但这是我的理解。  如果您使用Capybara作为登录的驱动程序,他会在HIS cookie中保留remember_token。但是,下一个PATCH请求将由另一个人提交,因为Capybara无法直接将该请求发送到Web服务器。在这种情况下,发送请求的人在用于登录的cookie中没有remember_token。这就是测试出错的原因。

这不是启动问题。