QA@IT

rspecで、Omniauthのログイン状態を再現したい

5141 PV

やりたいこと

Railsアプリケーションの認証をOmniauthで行っています。さて、このアプリケーションで、rspecを使って、ログインの有無による振る舞いの違いをテストする方法を知りたいです。

やったけどうまくいかなかったこと

現状としては、以下の通りです。

ブラウザでは問題なく動作している

アプリケーションにブラウザでアクセスすると、ログインできることは確認しており、

=debug(p session)

の結果は

{"session_id"=>"****", "_csrf_token"=>"****=", "user_id"=>1}

のように、表示され、一番下のテストに記述したあるべき振る舞いも実現されています。

rspecでログイン状態の作り方がわからない

しかし、rspecでユーザーのログイン状態を作ることができません。

具体的には、一番下のテストを書いているのですが、

Failure/Error: response.status.should be(200)
    expected #<Fixnum:401> => 200
    got #<Fixnum:605> => 302

となってひとつめのテストが通りません。

コメントアウトされている

p session

をコメントアウトせずに実行させると

#<Rack::Session::Abstract::SessionHash:0x3fc827f4a7ac not yet loaded>

となり、ログイン状態が作れていないと考えています。

実際のテスト

require 'spec_helper'

describe "Shelves" do
  before(:each) do
    @user = FactoryGirl.create(:user)
    @item = FactoryGirl.create(:item)
    @user.items << @item
    OmniAuth.config.test_mode = true
    OmniAuth.config.mock_auth[:facebook] = FactoryGirl.attributes_for(:user)
  end
  describe "GET /shelves" do
    context "when logged in as a valid user," do
      it "should show the items of current user" do
        get "/auth/facebook"
        get shelves_path
        # p session
        # p @user
        # p @item
        response.status.should be(200)
        response.body.should include(@item.name)
      end
    end
    context "when not logged in," do
      it "should redirect to items index page" do
        get shelves_path

        response.status.should be(302)
        response.should redirect_to(items_path)

      end
    end
  end
end

回答

controller spec は Rack middleware を経由しないため、/auth/:provider にアクセスしても OmniAuth に処理がいくことはありません。

コントローラのテストの前提条件としてログインが必要ということでしたら、ログインした状態に見せかけるのがいいと思います (= ログインのフロー自体はテストしない)。例えば #current_user というメソッドでログイン状態を判定しているなら、以下のようになるでしょう:

before(:each) do
  ...

  controller.stub(:current_user) { @user }
end

ログインのフローを含めてテストしたいということでしたら、インテグレーションテストのための仕組みを使う必要があります (例えば Request Spec)。この場合、OmniAuth.config.test_mode = true は期待通りに動作するはずです。

編集 履歴 (0)
  • ありがとうございます。controller specとrequest specを混同してしまっていました。request specで書いてみたいと思います。 -

以下の通りでいけました。ありがとうございました。


require 'spec_helper'

describe "Shelves" do
  before(:each) do
    @user = FactoryGirl.create(:user)
    @item = FactoryGirl.create(:item)
    @user.items << @item
    OmniAuth.config.test_mode = true
    OmniAuth.config.mock_auth[:facebook] = FactoryGirl.attributes_for(:user)

  end

  describe "GET /shelves" do
    context "when logged in as a valid user," do
      it "should show the items of current user" do
        get "/auth/facebook"
        visit shelves_path
        page.should have_content(@item.name)
      end
    end
  end
end
編集 履歴 (1)
ウォッチ

この質問への回答やコメントをメールでお知らせします。