[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

その他

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

夏のTechRachoフェア2019

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ