こんにちは、hachi8833です。引き続きDevise How-ToのOmniAuthシリーズをお送りします。
概要
- 原文: Integration Testing(OmniAuthのWikiより)
- リビジョン: 12 Nov 2016 · 21 revisions
読みやすさのため、横に長いコードを途中で改行しています。
原文の更新や誤りにお気づきの場合は、ぜひ@techrachoまでお知らせください。更新いたします。
OmniAuth: 結合テスト(翻訳)
OmniAuthには、結合テスト(integration test: 統合テストとも)で認証フローをモックに差し替える方法がいくつか用意されています。
OmniAuth.config.test_mode
OmniAuthのテストモードを有効にするには、以下のように設定します。
OmniAuth.config.test_mode = true
訳注: 設定の記述場所はspec/support/omniauth.rbやspec/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を特定の状態にリセットするには、テストスイートレベルの設定(setup
やbefore(: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
その他
- [Devise How-To]ユーザー登録ページへのルーティングをカスタマイズする(翻訳)
- [Devise How-To] sign_inとsign_outのデフォルトルーティングを変更する(翻訳)
- [Devise How-To]ユーザーのパスワードを自動生成する(シンプルな登録方法)(翻訳)
- Rails4: 古いdeviseのパスワードを新しいdeviseで使う方法
- Rails 3.1.0.rc8にしようとしたらdeviseが違うバージョンのbcryptに依存していてアップデートできない
- [Rails 3] deviseで使うモデルにfind_by_で始まる名前のscopeを定義するとrake db:migrate:resetが通らない
- [Rails 3] 失敗しないmigrationを書こう
- [Rails 3] Appサーバが複数だとdevise_openid_authenticatableで認証できない