2011年9月8日木曜日

Rails3を初歩から学ぶ #17 インテグレーションテスト

この一連のエントリは
Ruby on Rails 3 Tutorial: Learn Rails by Example (Addison-Wesley Professional Ruby Series)
で参考に学んだことを凝縮してお送りしています。

未認証状態で「http://localhost:3000/users/」でアクセスするとフィルタで弾かれてサインイン画面へ遷移します。
そしてサインインするとユーザーごとの個人ページ(/users/:id)に遷移します。
これはちょっと不親切ですね。
最初にindexを表示しようとしていたのだから、そこへ行ってあげるのが親切でしょう。
じゃあそうしましょうか、というとき、これはどうやって検証すればよいのでしょうか。
ここで検証したいのは「未認証状態でindex -> サインインページへ遷移 -> サインインしてindexへ」という一連の流れを検証したいのですが今までのRSpecファイルでは対応できそうもありません。

そこで登場するのがインテグレーションテストです。
まずはrailsコマンドでインテグレーションテストを生成します。
rails generate integration_test user_session
generateコマンドにintegration_testを指定するとインテグレーションテストを生成します。ここではuser_sessionという名前で生成しています。
実際に生成されるのは spec/requests/user_session_spec.rb です。早速編集しましょう。

# -*- coding: utf-8 -*-
require 'spec_helper'
describe "サインイン後の遷移先" do
it "サインイン前に要求したページに遷移する" do
user = Factory(:user)
visit users_path
#この段階でサインインページにリダイレクトされているハズ
fill_in :name, :with => user.name
fill_in :password, :with => user.password
click_button
#サインイン前に要求していたindexに遷移すること
response.should render_template('users/index')
end
end
だいたい英文のようになっているので何しているか分かると思います。
それでは実装に入りましょう。まずはアクセス拒否時にアクセス先を記録する処理と、サインイン後にリダイレクト先を決定するヘルパメソッドを追加します。
app/helpers/session_helper.rb に以下のメソッドを追加します。

def deny_access
store_location
redirect_to new_session_path, :notice => "サインインしてください"
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
clear_return_to
end
※以下2メソッドはprivateで定義する
def store_location
session[:return_to] = request.fullpath
end
def clear_return_to
session[:return_to] = nil
end

deny_accessメソッドは既に存在していますが赤文字部分を追加します。
このstore_locationメソッドでセッションに要求先URLを保存します。
そしてredirect_back_orメソッドでセッションをチェックして直前にアクセス拒否されていたら拒否されたページにリダイレクトしています。
リダイレクトしたらセッションからアクセス先情報を削除しています。
あとはサインイン成功時のリダイレクト処理をredirect_back_orに置き換えればOKです。
app/controller/sessions_controller.rbのcreateメソッドを以下の赤文字部分のように修正します。

def create
user = User.authenticate(params[:session][:name],
params[:session][:password])
if user.nil?
flash.now[:error] = "サインインできませんでした"
@title = "サインイン"
render 'new'
else
sign_in user
redirect_back_or user
end
end
これまでredirect_toとしていた箇所を先ほど追加したredirect_back_orに置き換えています。これでインテグレーションテストもパスします。
実際に動かして試してみましょう。

0 件のコメント:

コメントを投稿