コントローラーのテストで、Devise に適切にサインインさせようとすると、おかしな動作が発生しました。特定のケースでは機能するようですが、他のケースでは機能しないようです。これが Devise と FactoryGirl の間の相互作用なのか、それとも他の何かが働いているのかはわかりません。
まず、ここに私の工場があります:
factory :advisor do
name "Jason Jones"
association :user
initialize_with {Advisor.find_or_create_by_name('Jason Jones')}
end
factory :client do
name "Rich Homeowner"
association :advisor
end
factory :user do
email "jason@jones.com"
password "testpassword"
initialize_with {User.find_or_create_by_email('jason@jones.com')}
end
私のコントローラー:
class ClientsController < ApplicationController
before_filter :authenticate_user!
def destroy
@client = current_user.advisor.clients.where(:id => params[:id]).first
@client.destroy
flash[:notice] = 'Client deleted.'
redirect_to clients_path
end
そして私のコントローラーテスト:
describe "DELETE destroy" do
it "should delete a client" do
a = FactoryGirl.create(:advisor)
c = FactoryGirl.create(:client, :advisor => a)
login_user(a.user)
expect{
delete :destroy, :id => c.id
response.should be_redirect
assigns(:client).should eq(c)
}.to change(Client, :count).by(-1)
end
end
login_user 仕様ヘルパーは、ファンキーになる場所です。以下の行のコメントを外して、ユーザーを強制的に FactoryGirl オブジェクトに設定すると、テストは成功します。コメントのままにしておくと、Devise は渡されたユーザーとしてサインインしようとします (デバッグによって確認したのは、DB 内の同じユーザーです) が、実際にはサインインしません。sign_in 呼び出しは、実際には両方のケースで同じ配列を返します。ですが、Devise がログイン ページにリダイレクトするため、実行パスをたどることに基づいて、コントローラー コードが実行されることはありません。
def login_user(user=nil)
@request.env["devise.mapping"] = Devise.mappings[:user]
if user.nil?
user = FactoryGirl.create(:user)
end
# user = FactoryGirl.create(:user) # uncommenting this line causes test to pass
sign_in user
end
sign_in を正しく機能させるにはどうすればよいですか?
記録として、Rails の TDD に関して言えば、実際のコードが正しく動作するようになるまでに 10 分を費やし、テスト コードが想定どおりに動作するようになるまでに 2 時間かかりました。