3

コントローラーのテストで、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 時間かかりました。

4

1 に答える 1

4

私は最近、TDDの哲学を飲み込もうとし始め、あなたが最初にしたのとまったく同じ感覚を持っていたことを認めます。あなたの時間の見積もりはかなり正確に見えます。10分の開発と2時間のテストケースの実装です。私の最初のアドバイスは、人生の多くのことのように、それは良くなるということです。一見無害に見える変更を初めて行ったとき、テスト回帰の半分を破ったことに気づき、ピルを服用してよかったと思います。

Deviseそうは言っても、なぜうまくいかないのかと尋ねているので、これは警官のように聞こえます。私の答えは、気にしないでください。明らかにあなたは何か間違ったことをしているので、与えられた情報からそれが何であるかはわかりませんが、とにかく助けることができると思います。

私が上で間違っていると思う唯一のことは、あなたのスペックが少なくとも4つのことをテストしているということです:

  1. 応答はリダイレクトです。
  2. @client割り当てられています。
  3. AClientが破壊されます。
  4. Devise適切な認証を提供しています。

仕様では、1つのことと1つのことだけをテストする必要があります。もっとテストしたくなるかもしれませんが、お勧めしません。キュウリまたは他の統合テストは、多くのものをテストしますが、仕様はテストしません。

Deviseここでテストする必要があるものではないので、stubそれを試してみてください。私はこのようなものがうまくいくと思います:

before :each do
  @advisor = FactoryGirl.create(:advisor)
  controller.stub(:authenticate_user!).and_return(true)
  controller.stub(:current_user).and_return(@advisor.user)
end

この後、テストしている3つのものに対して3つの異なるit "should" doブロックを作成します。

associationもう1つのヒントは、を定義するときに指定する必要はないと思いますFactoryGirl factory。これは、ポリモーフィックな関連付けにのみ必要だと思います。通常、値なしでアソシエーションの名前を指定するだけで、同じ名前でファクトリが実行されます。無限ループに注意してください。

それがお役に立てば幸いです。

于 2013-01-27T06:16:52.477 に答える