2011-04-22 20 views
2

私は明らかに認証にDeviseを使用しています。私がしようとしているのは、メソッドがユーザーオブジェクトに対して呼び出されたかどうかをテストすることです。だから私のスペックは次のようになります。Devise、Rspec、ユーザーの期待

it "should retrieve something for user" do 
    @user = Factory.create(:user) 
    sign_in @user 
    @user.expects(:something) 
    get :manage 
end 

私が持っている問題は、私が行う場合を除きを期待が失敗している:sign_inの@userが工夫されている場合、コントローラ上のCURRENT_USERコールを偽造

it "should retrieve something for user" do 
    @user = Factory.create(:user) 
    sign_in @user 
    controller.stubs(:current_user).returns @user 
    @user.expects(:something) 
    get :manage 
end 

は陳腐ようですテストヘルパー。デバッガを掘り下げた後も、@userが実際に返されているcurrent_userを偽造していないときに表示されるので、なぜ期待が満たされていないのかわかりません。

アイデア?

答えて

3

現在のユーザーは、セッションに格納する前にシリアル化されています。おそらく、ActiveRecordのユーザーモデルのために、それはユーザーのIDを格納しています:

https://github.com/plataformatec/devise/blob/master/lib/devise/test_helpers.rb#L49

これはあなたのコントローラが再びユーザーをフェッチするときことを意味します

https://github.com/plataformatec/devise/blob/master/lib/devise/controllers/helpers.rb#L47-49

それはセッション中のuser_idを見つけることですデータベースからユーザーを再フェッチすることができます。

これは、コントローラの#current_userによって返されたUserオブジェクトが、テストで#sign_inに渡された@userとは異なるRubyオブジェクトであることを意味します。したがって、スタブと1つのオブジェクトからの期待値は、

私はDevise/Wardenを広範囲に使用していませんが、これが起こっていることは間違いありません。 2つのインスタンスで#object_idを印刷して、これを確認することができます。

気むずかしセマンティクスアップデート2014年2月:

、ここにあなたのコントローラ上の細かなアプローチを#current_userをされたスタブテスト中のシステムの「境界」のあなたの定義に依存(SUT) - すなわち、あなたのコントローラ。 #current_userメソッドがDeviseによって定義され、Deviseによってコントローラに組み込まれていると仮定すると、#current_userはSUTの外部にあり、したがってスタブのためのフェアゲームの外にあると主張できます。

また、@userオブジェクトを返すように、User.findをスタブするなど、Deviseがアクセスしている下層(ActiveRecord)をスタブすることもできます。これは、あなたの仕様が動作実装とDevise実装の両方をテストしていることを意味します。そのため、仕様の変更は後で変更されます。

User.find(args)を使用し、そのメソッドをスタブして、その後、Deviseの後のバージョンをUser.where(args).first()に変更しました。コードは変更されていませんが、基礎となるライブラリがあり、仕様が失敗します。非常に一般的にこの考え方を考えてみると、HTTPレスポンスを模倣してHTTPライブラリーを後でスワップできるようにWebMockでスタブするのではなく、生のHTTPレスポンスを模倣することを考えています。おそらくこのDeviseの質問は1つに数えられます)。

+0

昨夜の掘削の後、あなたは正しいと思われます!情報をありがとう。 –

+0

最終的に何時間もの検索の後にソリューションがあります。ありがとうございます! – lambinator

関連する問題