RSpec と Capybara を使用すると、興味深いテスト失敗モードが得られます。これは、テスト ケース内の行のいくつかの微妙な再配置で解消されます...問題にならないものです。
独自の認証システムを開発しています。現在動作しており、ブラウザでログイン/アウトでき、セッションも動作します。ただし、これをテストしようとすると失敗します。(一見) 無関係な呼び出しの順序に依存しているように見える、よく理解できないことが起こっています。
require 'spec_helper'
describe "Sessions" do
it 'allows user to login' do
#line one
user = Factory(:user)
#For SO, this method hashes the input password and saves the record
user.password! '2468'
#line two
visit '/sessions/index'
fill_in 'Email', :with => user.email
fill_in 'Password', :with => '2468'
click_button 'Sign in'
page.should have_content('Logged in')
end
end
そのままでは、そのテストは失敗します...ログインは失敗します。スペックとコントローラーの両方に「デバッガー」呼び出しを挿入した後、理由がわかります。コントローラーに関する限り、ユーザーはデータベースに挿入されていません。
ApplicationController に追加する編集
class ApplicationController < ActionController::Base
helper :all
protect_from_forgery
helper_method :user_signed_in?, :guest_user?, :current_user
def user_signed_in?
!(session[:user_id].nil? || current_user.new_record?)
end
def guest_user?
current_user.new_record?
end
def current_user
@current_user ||= session[:user_id].nil? ? User.new : User.find(session[:user_id])
rescue ActiveRecord::RecordNotFound
@current_user = User.new
flash[:notice] = 'You\'ve been logged out.'
end
end
class SessionsController < ApplicationController
def login
user = User.where(:email=>params[:user][:email]).first
debugger ###
if !user.nil? && user.valid_password?(params[:user][:password])
#engage session
else
#run away
end
end
def logout
reset_session
redirect_to root_path, :notice => 'Logget Out.'
end
end
コンソールの上記のブレークポイントで:
1.9.2 vox@Alpha:~/Sites/website$ rspec spec/controllers/sessions_controller_spec.rb
/Users/vox/Sites/website/app/controllers/sessions_controller.rb:7
if !user.nil? && user.valid_password?(params[:user][:password])
(rdb:1) irb
ruby-1.9.2-p180 :001 > User.all.count
=> 0
ruby-1.9.2-p180 :002 >
ただし、テストで数行を並べ替えて、「2」行を「1」行の上に配置すると、次のようになります。
describe "Sessions" do
it 'allows user to login' do
#line two
visit '/sessions/index'
#line one
user = Factory(:user)
#For SO, this method hashes the input password and saves the record
user.password! '2468'
fill_in 'Email', :with => user.email
fill_in 'Password', :with => '2468'
click_button 'Sign in'
page.should have_content('Logged in')
end
end
コンソールでこれを取得します(上記と同じブレークポイント):
1.9.2 vox@Alpha:~/Sites/website$ rspec spec/controllers/sessions_controller_spec.rb
/Users/vox/Sites/website/app/controllers/sessions_controller.rb:7
if !user.nil? && user.valid_password?(params[:user][:password])
(rdb:1) irb
ruby-1.9.2-p180 :001 > User.all.count
=> 1
簡潔にするために、ユーザー オブジェクトのコンテンツの完全なダンプは省略しましたが、テストが期待どおりに完了することは保証できます。
テストに合格するために行を交換するというこの動作は、これらのコマンドで何が行われるべきかについての私の考えとはあまり一致せず、他の領域での私のテストにとってかなりの負担になることが証明されています。
ここで何が起こっているかについてのヒントはありますか?
この問題を提示するアイデアについて Google と SO を精査しましたが、RSpec/Capybara と Sessions に関する SO の質問に事欠きません。しかし、何もぴったりとは思えませんでした。
ご覧いただきありがとうございます。
アップデート
ブレークポイント (visit 呼び出しの直前) といくつかのデバッグをテストに追加し、次のように戻ってきました。
(rdb:1) user
#<User id: 1, login_count: 1, email: "testuser1@website.com", encrypted_password: "11f40764d011926eccd5a102c532a2b469d8e71249f3c6e2f8b...", salt: "1313613794">
(rdb:1) User.all
[#<User id: 1, login_count: 1, email: "testuser1@website.com", encrypted_password: "11f40764d011926eccd5a102c532a2b469d8e71249f3c6e2f8b...", salt: "1313613794">]
(rdb:1) next
/Users/vox/Sites/website/spec/controllers/sessions_controller_spec.rb:19
fill_in 'Email', :with => user.email
(rdb:1) User.all
[]
明らかに、visit の途中で何かが Factory Girl にユーザー オブジェクトの処理が完了したことを伝え、それで彼女はそれを削除するのでしょうか?
編集test.log を注意深く調べた後、何も削除を発行していません。だから私は多かれ少なかれ振り出しに戻っています。