0
0

More than 3 years have passed since last update.

Railsチュートリアル 第10章 フレンドリーフォワーディングの追加演習 - フレンドリーフォワーディングのリダイレクト先のURLが正しく渡されていることのテスト(editアクション編)

Last updated at Posted at 2019-11-24

何についての記事か

「Railsチュートリアル 第10章 演習 - フレンドリーフォワーディング」の発展学習となります。

同演習には、「渡されたURLに初回のみ転送されていることを確認する。具体的には、リダイレクトのURLはデフォルト (プロフィール画面) に戻っていることを確認する。」という内容の出題があります。それであれば、逆に「『ログインしていない状態でユーザー情報編集ページにアクセスしようとした』という状況で、フレンドリーフォワーディングのリダイレクト先のURLが正しく渡されていること」のテストも必要なはずです。

というわけで、発展学習としてQiita記事を書いてみました。

内容

フレンドリーフォワーディングのリダイレクト先のURLを保存する処理はどこにあるか

現在の実装では、「Usersコントローラーのeditアクションが呼び出される前には、同コントローラーのlogged_in_user」メソッドが呼び出されるようになっています。そのコードは以下のとおりです。

UsersController#logged_in_user
def logged_in_user
  unless logged_in?
    store_location
    flash[:danger] = "Please log in."
    redirect_to login_url
  end
end

「ログインしていない状態でUsersコントローラーのeditアクションが呼び出された」という状況においては、以下のコードが実行されます。

store_location
flash[:danger] = "Please log in."
redirect_to login_url

このうち、フレンドリーフォワーディングのリダイレクト先のURLを一時cookiesに保存するのは、store_locationメソッドですね。当該メソッドは、Sessionsヘルパーに実装されています。

store_locationメソッドの実装

SessionsHelper#store_location
def store_location
  session[:forwarding_url] = request.original_url if request.get?
end

「HTTPリクエストがGETである場合のみ、一時cookiesにフレンドリーフォワーディングのリダイレクト先のURLが保存される」という実装です。

フレンドリーフォワーディングのリダイレクト先のURLを保存する処理に対応するテスト

上述コードに対応するテストコードは、test/controllers/users_controller_test.rb内にあります。editアクションに対応するテストは"should redirect edit when not logged in"です。

test/controllers/users_controller_test.rb(抜粋)
test "should redirect edit when not logged in" do
  get edit_user_path(@user)
  assert_not flash.empty?
  assert_redirected_to login_url
end

当該テストに記述を追加すれば、「『ログインしていない状態でユーザー情報編集ページにアクセスしようとした』という状況で、フレンドリーフォワーディングのリダイレクト先のURLが正しく渡されていること」がテストできるはずです。

実際に追加する記述は以下のようになります。

test/controllers/users_controller_test.rb(抜粋)
  test "should redirect edit when not logged in" do
    get edit_user_path(@user)
    assert_not flash.empty?
    assert_redirected_to login_url
+   assert_not_nil session[:forwarding_url]
  end

前提 - テストコードの特定行に対してテストを実行する

例えば、test/controllers/users_controller_test.rbの15行目に対応するテストを実行するには、rails testコマンドを以下のように呼び出せばOKです。

# rails test test/controllers/users_controller_test.rb:15

store_locationメソッドが呼び出されない場合に対するテスト

store_locationメソッドが呼び出されない場合」を再現する

UsersController#logged_in_userメソッドで、store_locationメソッドが実行されないようにすればOKです。すぐにもとに戻すので、今回は「ソースコードからコメントアウト」という方法をとります。

app/controllers/users_controller.rb
  class UsersController < ApplicationController
    before_action :logged_in_user, only: [:edit, :update]
    before_action :correct_user,   only: [:edit, :update]

    ...略

    private

      ...略

      # beforeアクション

      # ログイン済みユーザーかどうか確認
      def logged_in_user
        unless logged_in?
-         store_location
+         # store_location
          flash[:danger] = "Please log in."
          redirect_to login_url
        end
      end

      ...略
  end

store_locationメソッドが呼び出されない場合」に、editアクションに対するテストが失敗することを確認する

editアクションに対するテストには、「should redirect edit when not logged in」という名前がついています。私の環境では、テスト「should redirect edit when not logged in」の始まりは、test/controllers/users_controller_test.rbの15行目となっています。

test/controllers/users_controller_test.rb(15行目)
test "should redirect edit when not logged in" do

この行に対応するテストを実施してみます。

# rails test test/controllers/users_controller_test.rb:15
Running via Spring preloader in process 1220
Started with run options --seed 40280

 FAIL["test_should_redirect_edit_when_not_logged_in", UsersControllerTest, 0.5344693000079133]
 test_should_redirect_edit_when_not_logged_in#UsersControllerTest (0.54s)
        Expected nil to not be nil.
        test/controllers/users_controller_test.rb:19:in `block in <class:UsersControllerTest>'

  5/5: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.53826s
1 tests, 3 assertions, 1 failures, 0 errors, 0 skips

test/controllers/users_controller_test.rbの19行目でテストが失敗しましたね。当該行には、以下のコードが記述されています。

test/controllers/users_controller_test.rb(19行目)
assert_not_nil session[:forwarding_url]

たった今追加したコードですね。想定したテストが正しく行えていることがわかりました。

UsersController#logged_in_userメソッドを元に戻す

テストが正しく実装できていることがわかったので、UsersController#logged_in_userメソッドは元に戻しておきましょう。

app/controllers/users_controller.rb
  class UsersController < ApplicationController
    before_action :logged_in_user, only: [:edit, :update]
    before_action :correct_user,   only: [:edit, :update]

    ...略

    private

      ...略

      # beforeアクション

      # ログイン済みユーザーかどうか確認
      def logged_in_user
        unless logged_in?
-         # store_location
+         store_location
          flash[:danger] = "Please log in."
          redirect_to login_url
        end
      end

      ...略
  end

GETリクエストに対して、一時cookiesにリダイレクト先のURLが保存されない場合に対するテスト

GETリクエストに対して、一時cookiesにリダイレクト先のURLが保存されない場合」を再現する

SessionsHelper#store_locationメソッドの記述を変更します。

app/helpers/sessions_helper.rb
  module SessionsHelper
    ...略

    # アクセスしようとしたURLを覚えておく
    def store_location
-     session[:forwarding_url] = request.original_url if request.get?
+     session[:forwarding_url] = request.original_url if !request.get?
    end
  end

request.get?!request.get?に書き換えることにより、「GETリクエスト以外のリクエストに対して、一時cookiesにリダイレクト先のURLを保存する」という動作にしています。

GETリクエストに対して、一時cookiesにリダイレクト先のURLが保存されない場合」に、editアクションに対するテストが失敗することを確認する

# rails test test/controllers/users_controller_test.rb:15
Running via Spring preloader in process 1272
Started with run options --seed 50959

 FAIL["test_should_redirect_edit_when_not_logged_in", UsersControllerTest, 0.5778716999921016]
 test_should_redirect_edit_when_not_logged_in#UsersControllerTest (0.58s)
        Expected nil to not be nil.
        test/controllers/users_controller_test.rb:19:in `block in <class:UsersControllerTest>'

  5/5: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.58515s
1 tests, 3 assertions, 1 failures, 0 errors, 0 skips

先ほどと同じく、test/controllers/users_controller_test.rbの19行目でテストが失敗しました。想定したテストが正しく行えているといえます。

SessionsHelper#store_locationメソッドを元に戻す

テストが正しく実装できていることがわかったので、SessionsHelper#store_locationメソッドは元に戻しておきましょう。

app/helpers/sessions_helper.rb
  module SessionsHelper
    ...略

    # アクセスしようとしたURLを覚えておく
    def store_location
-     session[:forwarding_url] = request.original_url if !request.get?
+     session[:forwarding_url] = request.original_url if request.get?
    end
  end

実装が正しいことの確認

改めて、test/controllers/users_controller_test.rbの15行目に対応するテストを実行します。

# rails test test/controllers/users_controller_test.rb:15
Running via Spring preloader in process 1298
Started with run options --seed 23019

  5/5: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.66698s
1 tests, 3 assertions, 0 failures, 0 errors, 0 skips

テストは無事成功しました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0