Tech Racho エンジニアの「?」を「!」に。
  • 開発

[Devise How-To] OmniAuth: 結合テスト(翻訳)

こんにちは、hachi8833です。引き続きDevise How-ToのOmniAuthシリーズをお送りします。

Devise Wikiもくじリンク

  1. 「ワークフローのカスタマイズ」
  2. 「認証方法のカスタマイズ」「OmniAuth」
  3. 「ビュー/コンテンツのカスタマイズ」「特権/認証」
  4. 「テスト」「特殊な設定」
  5. 「アプリでのその他の設定」「JavaScript」
  6. 「他の認証プラグインからの移行」「アップグレード」

概要

読みやすさのため、横に長いコードを途中で改行しています。

原文の更新や誤りにお気づきの場合は、ぜひ@techrachoまでお知らせください。更新いたします。

OmniAuth: 結合テスト(翻訳)

OmniAuthには、結合テスト(integration test: 統合テストとも)で認証フローをモックに差し替える方法がいくつか用意されています。

OmniAuth.config.test_mode

OmniAuthのテストモードを有効にするには、以下のように設定します。

OmniAuth.config.test_mode = true

訳注: 設定の記述場所はspec/support/omniauth.rbspec/support/omniauth.rbなどです。

テストモードが有効になると、後述の認証ハッシュのモックを用いるためにOmniAuthへのリクエストはすべてスキップされます。たとえば/auth/providerへのリクエストは即座に/auth/provider/callbackにリダイレクトされます。

OmniAuth.config.mock_auth

#mock_authを使うと、結合テスト中に認証プロバイダごとの認証ハッシュやデフォルトの認証ハッシュを返すことができます。以下は設定例です。

OmniAuth.config.mock_auth[:twitter] = OmniAuth::AuthHash.new({
  :provider => 'twitter',
  :uid => '123545'
  # (省略)
})

:defaultをキーを設定すると、認証プロバイダが指定されていない場合にデフォルトの認証プロバイダを返します。モック認証ハッシュが設定されてテストモードになると、OmniAuthへのすべてのリクエストに対してモックの認証ハッシュが返されるようになります。

OmniAuth.config.add_mock

#add_mockメソッドは、以下のように認証プロバイダの新しいモックをその場で追加するときにも使えます。設定した情報はデフォルトの情報と自動的にマージされるので、正しいレスポンスが返されます。

OmniAuth.config.add_mock(:twitter, {:uid => '12345'})

モックが失敗する場合

認証プロバイダのモックを以下のようにハッシュではなくシンボルで設定すると、モックが失敗してエラーメッセージが表示されます。

OmniAuth.config.mock_auth[:twitter] = :invalid_credentials

失敗の場合、 /auth/failure?message=invalid_credentialsにリダイレクトされます。

デフォルトのOmniAuthは、developmentモードとtestモードで無効な認証情報に対して例外をraiseします。developmentモードとtestモードで失敗したときに/auth/failureエンドポイントにリダイレクトしたい場合は、以下のコードを追加します。

OmniAuth.config.on_failure = Proc.new { |env|
  OmniAuth::FailureEndpoint.new(env).redirect_to_failure
}

クリーンアップ

テストとテストの合間にOmniAuthを特定の状態にリセットするには、テストスイートレベルの設定(setupbefore(:each)など)で以下を実行します。

OmniAuth.config.mock_auth[:twitter] = nil

コントローラの設定

OmniAuthのテストでは、コントローラで以下の2つの環境変数を設定する必要があります。以下はTwitter OmniAuthをRSpecでテストする場合のサンプルです。

before do 
  request.env["devise.mapping"] = Devise.mappings[:user] # Deviseを使う場合
  request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:twitter] 
end

新しいバージョンのRSpecではrequestオブジェクトにアクセスできません。request specを使う場合は以下のようにします。

before do
  Rails.application.env_config["devise.mapping"] = Devise.mappings[:user] # Deviseを使う場合
  Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:twitter]
end

上のようにすることで、以下のサンプルのようなルーティングエラーを防止できます。

Failure/Error: get :twitter
AbstractController::ActionNotFound:
  Could not find devise mapping for path "/users/auth/twitter/callback".
  Maybe you forgot to wrap your route inside the scope block? For example:
    devise_scope :user do
      match "/some/route" => "some_devise_controller"
    end

関連記事(Devise)

OminiAuth

その他


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。