LoginSignup
0
2

More than 3 years have passed since last update.

Railsチュートリアル 第11章 アカウントの有効化 - /users と /users/:id に対する統合テスト

Posted at

何について書いているか

Railsチュートリアル第11章、演習 - 有効化のテストとリファクタリングのうち、3番目の演習内容について書いています。

ここまでの演習課題で変更したコードをテストするために、/users と /users/:id の両方に対する統合テストを作成してみましょう。

統合テストの作成

テストの名前はusers_activationとします。

# rails generate integration_test users_activation
Running via Spring preloader in process 14164
      invoke  test_unit
      create    test/integration/users_activation_test.rb

当該統合テストの前提となる実装を行う

fixtureに、有効でないユーザーを定義する

現状のfixtureには、有効でないユーザーは定義されていません。テストを実行する前に、まずは有効でないユーザーがRDB上に存在するよう、fixtureにユーザーを追加する必要があります。

fixtureで有効でないユーザーを生成する場合、例えば以下のようなYAMLが必要となります。

有効でないユーザーを生成するYAMLの例
not_activated:
  name: User Not activated
  email: example_foobar@example.org
  password_digest: <%= User.digest('password') %>
  activated: false
  activated_at: nil

ポイントは以下です。

  • activatedfalseであること
  • activated_atnilであること

UsersActivationTest#setupメソッド

実際のテストに先がけて、テストで使うユーザー情報をインスタンス変数に格納する必要があります。そうした処理は、テストのsetupメソッドで行うのでしたね。

UsersActivationTest#setup
  def setup
    @admin = users(:rhakurei)
    @user_not_activated = users(:not_activated)
  end

以下の処理を行っています。

  • 管理ユーザーを@adminとして定義する
    • /users を表示するために、有効なユーザーが必要となる
  • 有効でないユーザーを@user_not_activatedとして定義する

必要なテストの内容

必要なテストの内容は以下になります。

  • /users で表示されるユーザー一覧に、有効でないユーザーが表示されないこと
  • /users/:id で有効でないユーザーを表示しようとしたときに、/ にリダイレクトされること

/users で表示されるユーザー一覧に、有効でないユーザーが表示されないこと

名前は「index should not include not activated user」としました

test "index should not include not activated user" do
  log_in_as(@admin)
  get users_path
  assert_select 'a[href=?]', user_path(@user_not_activated), count: 0
end

動作内容は以下となります。

  1. 管理ユーザーでログインする
  2. users_pathに対し、GETリクエストを送信する
  3. 有効でないユーザーのプロフィールページへのリンクが表示されていなければテスト成功

/users/:id で有効でないユーザーを表示しようとしたときに、/ にリダイレクトされること

名前は「show user who is not activated should redirect to root」としました。

test "show user who is not activated should redirect to root" do
  get user_path(@user_not_activated)
  assert_redirected_to root_url
end

動作内容は以下となります。

  1. 有効でないユーザーのuser_pathに対し、GETリクエストを送信する
  2. / にリダイレクトされればテスト成功

test/integration/users_activation_test.rbの全体像

test/integration/users_activation_test.rbの全体像は以下のようになります。

test/integration/users_activation_test.rb
require 'test_helper'

class UsersActivationTest < ActionDispatch::IntegrationTest
  def setup
    @admin = users(:rhakurei)
    @user_not_activated = users(:not_activated)
  end

  test "index should not include not activated user" do
    log_in_as(@admin)
    get users_path
    assert_select 'a[href=?]', user_path(@user_not_activated), count: 0
  end

  test "show user who is not activated should redirect to root" do
    get user_path(@user_not_activated)
    assert_redirected_to root_url
  end
end

この時点でテストは成功する

この時点で、test/integration/users_activation_test.rbを対象にテストを実行すると、問題なく成功します。

# rails test test/integration/users_activation_test.rb
Running via Spring preloader in process 14245
Started with run options --seed 11346

  2/2: [===================================] 100% Time: 00:00:03, Time: 00:00:03

Finished in 3.75769s
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips

逆にどのようなバグがあったらテストが失敗するのか

/users で表示されるユーザー一覧に、有効でないユーザーが表示される場合

仮に、UsersController#indexの実装が以下のようになっていたら、テストの結果はどうなるでしょう。

UsersController#index
def index
  @users = User.paginate(page: params[:page])
end

以下のようなメッセージが表示されてテストが失敗します。

# rails test test/integration/users_activation_test.rb
Running via Spring preloader in process 14284
Started with run options --seed 11740

  /0: [=---=---=---=---=---=---=---=---=---=-] 0% Time: 00:00:00,  ETA: ??:??:??
[8, 17] in /var/www/sample_app/test/integration/users_activation_test.rb
    8: 
    9:   test "index should not include not activated user" do
   10:     log_in_as(@admin)
   11:     get users_path
   12:     debugger
=> 13:     assert_select 'a[href=?]', user_path(@user_not_activated), count: 0
   14:   end
   15:   ...略
(byebug) user_path(@user_not_activated)
"/users/826701971"
 FAIL["test_index_should_not_include_not_activated_user", UsersActivationTest, 11.721780299965758]
 test_index_should_not_include_not_activated_user#UsersActivationTest (11.72s)
        Expected exactly 0 elements matching "a[href="/users/826701971"]", found 2..
        Expected: 0
          Actual: 2
        test/integration/users_activation_test.rb:13:in `block in <class:UsersActivationTest>'

  2/2: [===================================] 100% Time: 00:00:11, Time: 00:00:11

Finished in 11.76151s
2 tests, 2 assertions, 1 failures, 0 errors, 0 skips

/users/826701971 というのは、user_path(@user_not_activated)のことです(わかりやすくするために、ここではassert_selectの前にdebuggerで確認しています)。

なお、a[href="/users/826701971"]の数の「2」というのは、GET用のリンクとDELETE用のリンクで2つ、ということです。ログインユーザーが管理ユーザーでない場合、ここは「1」となるはずですね。

/users に有効でないユーザーが表示される - どう修正すればいいか

/index で有効なユーザーのみを表示するようにするためには、@usersを定義するメソッドチェーンにwhere(activated: true)が必要なのでしたね。

UsersController#index
  def index
-   @users = User.paginate(page: params[:page])
+   @users = User.where(activated: true).paginate(page: params[:page])   
  end

今度こそテストは成功するはずです。

# rails test test/integration/users_activation_test.rb
Running via Spring preloader in process 14323
Started with run options --seed 3334

  2/2: [===================================] 100% Time: 00:00:03, Time: 00:00:03

Finished in 3.32350s
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips

/users/:id で有効でないユーザーを表示しようとしたときに、/ にリダイレクトされない場合

仮に、UsersController#showの実装が以下のようになっていたら、テストの結果はどうなるでしょう。

UsersController#show
def show
  @user = User.find(params[:id])
end

以下のようなメッセージが表示されてテストが失敗します。

# rails test test/integration/users_activation_test.rb
Running via Spring preloader in process 14310
Started with run options --seed 41248

 FAIL["test_show_user_who_is_not_activated_should_redirect_to_root", UsersActivationTest, 2.460988399980124]
 test_show_user_who_is_not_activated_should_redirect_to_root#UsersActivationTest (2.46s)
        Expected response to be a <3XX: redirect>, but was a <200: OK>
        test/integration/users_activation_test.rb:17:in `block in <class:UsersActivationTest>'

  2/2: [===================================] 100% Time: 00:00:03, Time: 00:00:03

Finished in 3.07865s
2 tests, 2 assertions, 1 failures, 0 errors, 0 skips

「リダイレクトされるべき場面でリダイレクトされていない」という趣旨のメッセージですね。

有効でないユーザーを表示しようとしたときに、/ にリダイレクトされない - どう修正すればいいか

UsersController#showを以下のように修正します。

UsersController#show
  def show
    @user = User.find(params[:id])
+   redirect_to root_url unless @user.activated?
  end

今度こそテストは成功するはずです。

# rails test test/integration/users_activation_test.rb
Running via Spring preloader in process 14336
Started with run options --seed 35088

  2/2: [===================================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.52763s
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips

test/integration/users_index_test.rbにも修正が必要だった

テスト失敗の内容

fixtureに有効でないユーザーを含むようにすると、全体のテストが成功しなくなります。

# rails test
Running via Spring preloader in process 14362
Started with run options --seed 17156

 FAIL["test_index_as_admin_including_pagination_and_delete_links", UsersIndexTest, 6.323125800001435]
 test_index_as_admin_including_pagination_and_delete_links#UsersIndexTest (6.32s)
        Expected at least 1 element matching "a[href="/users/826701971"]", found 0..
        Expected 0 to be >= 1.
        test/integration/users_index_test.rb:16:in `block (2 levels) in <class:UsersIndexTest>'
        test/integration/users_index_test.rb:15:in `block in <class:UsersIndexTest>'

  46/46: [=================================] 100% Time: 00:00:07, Time: 00:00:07

Finished in 7.62021s
46 tests, 188 assertions, 1 failures, 0 errors, 0 skips

対応するテスト

test_index_as_admin_including_pagination_and_delete_links#UsersIndexTestに対応するソースコードは、test/integration/users_index_test.rbの以下の部分ですね。

test/integration/users_index_test.rb(抜粋)
test "index as admin including pagination and delete links" do
  log_in_as(@admin)
  get users_path
  assert_template 'users/index'
  assert_select 'div.pagination'
  first_page_of_users = User.paginate(page: 1)
  first_page_of_users.each do |user|
    assert_select 'a[href=?]', user_path(user), text: user.name
    unless user == @admin
      assert_select 'a[href=?]', user_path(user), text: 'delete'
    end
  end
  assert_difference 'User.count', -1 do
    delete user_path(@non_admin)
  end
end

原因と修正

原因は以下の行です。1ページ目に表示されるユーザーの組を、「有効でないユーザーを含む」という形で定義してしまっているためですね。

first_page_of_users = User.paginate(page: 1)

当該実装は、以下のように修正する必要があります。「1ページ目に表示されるユーザーの組に、有効なユーザーのみを含むようにする」という実装ですね。

- first_page_of_users = User.paginate(page: 1)
+ first_page_of_users = User.where(activated: true).paginate(page: 1)

全体としては以下の修正内容となります。

ruby
  test "index as admin including pagination and delete links" do
    log_in_as(@admin)
    get users_path
    assert_template 'users/index'
    assert_select 'div.pagination'
-   first_page_of_users = User.paginate(page: 1)
+   first_page_of_users = User.where(activated: true).paginate(page: 1)
    first_page_of_users.each do |user|
      assert_select 'a[href=?]', user_path(user), text: user.name
      unless user == @admin
        assert_select 'a[href=?]', user_path(user), text: 'delete'
      end
    end
    assert_difference 'User.count', -1 do
      delete user_path(@non_admin)
    end
  end

今度こそ全体のテストが成功する

当該修正を適用すれば、今度こそ全体のテストが成功するようになります。

# rails test
Running via Spring preloader in process 14401
Started with run options --seed 21435

  46/46: [=================================] 100% Time: 00:00:07, Time: 00:00:07

Finished in 7.06875s
46 tests, 197 assertions, 0 failures, 0 errors, 0 skips
0
2
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
2