Rails5でRails Tutorial（Rails4.2.6）をやってみた

## 投稿の目的
- Railsが、4.2.6から5になることで変わるポイントを記録すること

## 動機
- 以前にも[Rails Tutorial](http://railstutorial.jp")で勉強していました
- が、テストはそれ以降敬遠していた
- やはり自動でできるテストはせっかくある機能に任せるべきだと思うに至った

ということで、テストに関する知識を復習をして、<strong>"テストを書く→コードを書く"</strong>を習慣づけたいと思い改めてチュートリアルをやろうと思いました。それであれば、せっかくRails5がリリースされているので、Rails5で変わったことを忘れないように記録したいと思います。

チュートリアルをやりながら、気づいたら追記をしていきます。

## 環境
  - ubuntu 16.04
  - Rails 5.0.0.1
  - Ruby 2.3.1

## 3.3.1 最初のテスト
`rails generate`で作られた`static_pages_controller_test.rb`のコントローラーのテストファイルにおいて、ページを呼び出す`get`で設定する値がシンボルではなく、URLやPATHでないと`URI::InvalidURIError:         URI::InvalidURIError: bad URI(is not URI?)`というエラーが出てテストがfailする。

```ruby:test/controllers/static_pages_controller_test.rb
# Rails 4.2.6
require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  test "should get home" do
    get :home # <- ここ
    assert_response :success
  end

  test "should get help" do
    get :help # <- ここ
    assert_response :success
  end
end

# Rails 5.0.0.1
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get static_pages_home_url # <- ここ
    assert_response :success
  end

  test "should get help" do
    get static_pages_help_url # <- ここ
    assert_response :success
  end
end

```

継承されているclassが5で変わったことが影響しているのかな。あとで調べる。

<2016/9/8 追記>
## 5.3.4. リンクのテスト
統合テスト（integration test）を実行すると、次のエラーが出る。

```shell-session
ERROR["test_layout_links", SiteLayoutTest, 0.7033021890001692]
 test_layout_links#SiteLayoutTest (0.70s)
NoMethodError:         NoMethodError: assert_template has been extracted to a gem. To continue using it,
                add `gem 'rails-controller-testing'` to your Gemfile.
            test/integration/site_layout_test.rb:6:in `block in <class:SiteLayoutTest>'

```

[ここ](http://blog.bigbinary.com/2016/04/19/changes-to-test-controllers-in-rails-5.html)や[こちら](http://resocia.jp/column/4630/)にあるように、testについて、`assigns`や`assert_template`がrails5では非推奨になったためのようです。

エラーに書かれている通りに`gem 'rails-controller-testing'`をgemfileに追加してget xxxを修正して実行すると問題なくテストできました。

```ruby:static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = 'Ruby on Rails Tutorial Neo Sample App'
  end

  test "should get home" do
    get root_url
    assert_response :success
    assert_select "title", "#{@base_title}"
  end

  test "should get help" do
    get help_url
    assert_response :success
    assert_select "title", "Help | #{@base_title}"
  end

  test "should get about" do
    get about_url
    assert_response :success
    assert_select "title", "About | #{@base_title}"
  end

  test 'should get contact' do
    get contact_url
    assert_response :success
    assert_select 'title', "Contact | #{@base_title}"
  end
end

```

## 7.4.4. 成功時のテスト
以下のテストを実行すると、成功するものの要約すると3つのdeprecation warningが表示される。
　　1. httpリクエストのパラメータの設定方法が変更になり、パラメータを`params`に入れる。
　　2. `post_via_redirect`の代わりに`follow_redirect!`を利用する。

```shell-session
DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept only                ] 19% Time: 00:00:08,  ETA: 00:00:36
the following keyword arguments in future Rails versions:
params, headers, env, xhr, as

Examples:

get '/profile',
  params: { id: 1 },
  headers: { 'X-Extra-Header' => '123' },
  env: { 'action_dispatch.custom' => 'custom' },
  xhr: true,
  as: :json
 (called from block (2 levels) in <class:UsersSignupTest> at /home/ebill/work/neo_sample_app/test/integration/users_signup_test.rb:8)
DEPRECATION WARNING: `post_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior. (called from block (2 levels) in <class:UsersSignupTest> at /home/ebill/work/neo_sample_app/test/integration/users_signup_test.rb:19)
DEPRECATION WARNING: `request_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior. (called from block (2 levels) in <class:UsersSignupTest> at /home/ebill/work/neo_sample_app/test/integration/users_signup_test.rb:19)
DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept only
the following keyword arguments in future Rails versions:
params, headers, env, xhr, as

Examples:

get '/profile',
  params: { id: 1 },
  headers: { 'X-Extra-Header' => '123' },
  env: { 'action_dispatch.custom' => 'custom' },
  xhr: true,
  as: :json
 (called from block (2 levels) in <class:UsersSignupTest> at /home/ebill/work/neo_sample_app/test/integration/users_signup_test.rb:19)
  21/21: [===============================================================================================] 100% Time: 00:00:09, Time: 00:00:09

Finished in 9.07180s
21 tests, 41 assertions, 0 failures, 0 errors, 0 skips

```

```ruby:users_signup_test.rb（修正前）
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest
  test 'invalid signup information' do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, user: { name: '',
                               email: 'invalid@email.com',
                               password: 'foo',
                               password_confirmation: 'bar'}
    end
    assert_template 'users/new'
  end

  test 'valid signup information' do
    get signup_path
    assert_difference 'User.count', 1 do
      post_via_redirect users_path, user: { name: 'Example User',
                                            email: 'valid@email.com',
                                            password: 'password',
                                            password_confirmation: 'password'}
    end
    assert_template 'users/show'
  end
end

```

```rb:users_signup_test.rb（修正後）
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test 'invalid signup information' do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name: '',
                                         email: 'invalid@email.com',
                                         password: 'foo',
                                         password_confirmation: 'bar'}}
    end
    assert_template 'users/new'
  end

  test 'valid signup information' do
    get signup_path
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name: 'Example User',
                                         email: 'valid@email.com',
                                         password: 'password',
                                         password_confirmation: 'password'}}
      follow_redirect!
    end
    assert_template 'users/show'
  end
end

```

<2016/9/13追記>
## 9.2.1 ユーザーにログインを要求する
上述の7.4.4.で記載されているとおり、テストにおいて、httpリクエストのパラメータの渡し方が変更になっている。

```rb:修正前users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionController::TestCase

  def setup
    @user = users(:michael)
  end

  test "should get new" do
    get :new
    assert_response :success
  end

  test "should redirect edit when not logged in" do
    get :edit, id: @user
    assert_not flash.empty?
    assert_redirected_to login_url
  end

  test "should redirect update when not logged in" do
    patch :update, id: @user, user: { name: @user.name, email: @user.email }
    assert_not flash.empty?
    assert_redirected_to login_url
  end
end
```

```rb:修正後users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end

  test "should get new" do
    get signup_path
    assert_response :success
  end

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

  test "should redirect update when not logged in" do
    patch user_path(@user),  params: { user: { name: @user.name, email: @user.email } }
    assert_not flash.empty?
    assert_redirected_to login_url
  end
end

```

## 9.4.3. ユーザー削除のテスト
上述の7.4.4.で記載されているとおり、テストにおいて、httpリクエストのパラメータの渡し方が変更になっている。

```rb:修正前users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionController::TestCase

  def setup
    @user       = users(:michael)
    @other_user = users(:archer)
  end
  .
  .
  .
  test "should redirect destroy when not logged in" do
    assert_no_difference 'User.count' do
      delete :destroy, id: @user
    end
    assert_redirected_to login_url
  end

  test "should redirect destroy when logged in as a non-admin" do
    log_in_as(@other_user)
    assert_no_difference 'User.count' do
      delete :destroy, id: @user
    end
    assert_redirected_to root_url
  end
end
```

```rb:修正後users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest

  def setup
    @user       = users(:michael)
    @other_user = users(:archer)
  end
  .
  .
  .
  test "should redirect destroy when not logged in" do
    assert_no_difference("User.count") do
      delete user_path(@user)
    end
    assert_redirected_to login_url
  end

  test "should redirect destroy when logged in as a non-admin" do
    log_in_as(@other_user)
    assert_no_difference("User.count") do
      delete user_path(@user)
    end
    assert_redirected_to root_url
  end
end
```