35歳だけどRailsチュートリアルやってみた。[第4版 7章　7.3.4 失敗時のテスト解答例]

#はじめに
最近、プロジェクト管理業務が業務の大半を占めており、
プログラムを書く機会がなかなかありません。

このままだとプログラムがまったく書けない人になってしまう危機感（迫り来る35歳定年説）と、
新しいことに挑戦したいという思いから、
[Ruby on Rails チュートリアル実例を使ってRailsを学ぼう 第4版](https://railstutorial.jp/)を学習中です。
業務で使うのはもっぱらJavaなのですが、Rails楽しいですね。


これまでEvernoteに記録していましたが、ソースコードの貼付けに限界を感じたため、
Qiitaで自分が学習した結果をアウトプットしていきます。
（現時点で、7.3.4 失敗時のテストまで学習しているため、過去分も含めて今後はQiitaに以降予定です）

個人の解答例なので、誤りがあればご指摘ください。


##7.3.4 失敗時のテスト
###演習1
*リスト 7.20で実装したエラーメッセージに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.25にテンプレートを用意しておいたので、参考にしてください。*

エラー時のCSSクラスと、ID確認に加えて、
各エラーメッセージの有無を追加。

```/sample_app/test/integration/users_signup_test.rb
  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name: "",
                                  email: "user@invalid",
                                  password: "foo",
                                  password_confirmation: "bar" } }
    end
    assert_template 'users/new'
    assert_select 'div#error_explanation'
    assert_select 'div.field_with_errors'
    assert_select 'ul' do
      assert_select 'li', 'Name can\'t be blank'
      assert_select 'li', 'Email is invalid'
      assert_select 'li', 'Password confirmation doesn\'t match Password'
      assert_select 'li', 'Password is too short (minimum is 6 characters)'
    end
  end
```

###演習2
*未送信のユーザー登録フォームと送信直後のURLは、それぞれ /signup と /users になり、URLが異なっています。これは、リスト 5.43で追加した名前付きルートと、デフォルトのRESTfulなルーティング (リスト 7.3) を設定したことによって生じた差異です。リスト 7.26とリスト 7.27の内容を追加し、この問題を解決してみてください。うまくいけば、いずれのURLも /signup となるはずです。あれ、でもテストは greenのままになっていますね...、なぜでしょうか? (考えてみてください）*

以下の2ファイルを追加。

```/sample_app/config/routes.rb
・・・略・・・
  post '/signup', to: 'users#create'
```
```/sample_app/app/views/users/new.html.erb
・・・略・・・
    <%= form_for(@user, url: signup_path) do |f| %>
```

テスト実行。

```
yokoyan:~/workspace/sample_app (sign-up) $ rails test
Running via Spring preloader in process 6924
Started with run options --seed 57560

  19/19: [===================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.32792s
19 tests, 47 assertions, 0 failures, 0 errors, 0 skips
```

テスト結果がgreenなのは、テストケースの中で
名前付きルートusers_pathにpostでリクエストを送信しているため。
結果、createアクション（ユーザを作成するアクション）が動いている。


| HTTPリクエスト     |       URL         |    アクション　　    |名前付きルート|用途|
|:-----------------|------------------:|:------------------:|:-:|:-:|
| POST             |        /users     |        create      |users_path|ユーザーを作成するアクション|

現在のテストケース。

```/sample_app/test/integration/users_signup_test.rb
・・・略・・・
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name: "",
                                  email: "user@invalid",
                                  password: "foo",
                                  password_confirmation: "bar" } }
    end
```



###演習3
*リスト 7.25のpost部分を変更して、上の演習課題で作られた新しいURLに合わせてみましょう。また、テストが依然として greenのままになっている点も確認してください。*

users_pathにpostしていた箇所を、signup_pathに修正。

```/sample_app/test/integration/users_signup_test.rb
・・・略・・・
    assert_no_difference 'User.count' do
      post signup_path, params: { user: { name: "",
                                  email: "user@invalid",
                                  password: "foo",
                                  password_confirmation: "bar" } }
    end
```

テスト実行。
greenになることを確認。

```
yokoyan:~/workspace/sample_app (sign-up) $ rails test
Running via Spring preloader in process 7154
Started with run options --seed 3548

  19/19: [===================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.25066s
19 tests, 47 assertions, 0 failures, 0 errors, 0 skips
```

###演習4
*リスト 7.27のフォームを以前の状態 (リスト 7.20) に戻してみて、テストがやはり greenになっていることを確認してください。これは問題です! なぜなら、現在postが送信されているURLは正しくないのですから。assert_selectを使ったテストをリスト 7.25に追加し、このバグを検知できるようにしてみましょう (テストを追加して redになれば成功です)。その後、変更後のフォーム (リスト 7.27) に戻してみて、テストが green になることを確認してみましょう。ヒント: フォームから送信してテストするのではなく、’form[action="/signup"]’という部分が存在するかどうかに着目してテストしてみましょう。*

リスト7.20の状態に戻す。

```/sample_app/app/views/users/new.html.erb
・・・略・・・
    <%= form_for(@user) do |f| %>
```

テスト実行。
greenになることを確認。

```
yokoyan:~/workspace/sample_app (sign-up) $ rails test
Running via Spring preloader in process 1732
Started with run options --seed 13591

  19/19: [===================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.13653s
19 tests, 47 assertions, 0 failures, 0 errors, 0 skips

```

画面に表示されたフォーム部分のHTMLを確認。
action=/usersに対して、postしていることを確認。

```
・・・略・・・
<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="ef8dxHvKVDJUk1492ajabp7JpO3z5r3jPJokTlncPOhAps7rXszZ3Lipehod62SGD7k0i0aCw3V7578U4LEZ0w==">
      
      
      <label for="user_name">Name</label>
      <input class="form-control" type="text" name="user[name]" id="user_name">
      
      <label for="user_email">Email</label>
      <input class="form-control" type="email" name="user[email]" id="user_email">
      
      <label for="user_password">Password</label>
      <input class="form-control" type="password" name="user[password]" id="user_password">
      
      <label for="user_password_confirmation">Confirmation</label>
      <input class="form-control" type="password" name="user[password_confirmation]" id="user_password_confirmation">
      
      <input type="submit" name="commit" value="Create my account" class="btn btn-primary" data-disable-with="Create my account">
</form>
```

テストコードを追加。

```/sample_app/test/integration/users_signup_test.rb
  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post signup_path, params: { user: { name: "",
                                  email: "user@invalid",
                                  password: "foo",
                                  password_confirmation: "bar" } }
    end
    assert_template 'users/new'
    assert_select 'div#error_explanation'
    assert_select 'div.field_with_errors'
    assert_select 'ul' do
      assert_select 'li', 'Name can\'t be blank'
      assert_select 'li', 'Email is invalid'
      assert_select 'li', 'Password confirmation doesn\'t match Password'
      assert_select 'li', 'Password is too short (minimum is 6 characters)'
    end
    assert_select 'form[action="/signup"]'
  end
```

再度テストを実行。
redになることを確認。

```
yokoyan:~/workspace/sample_app (sign-up) $ rails test
Running via Spring preloader in process 2967
Started with run options --seed 12420

 FAIL["test_invalid_signup_information", UsersSignupTest, 1.0442516568582505]
 test_invalid_signup_information#UsersSignupTest (1.04s)
        Expected at least 1 element matching "form[action="/signup"]", found 0..
        Expected 0 to be >= 1.
        test/integration/users_signup_test.rb:25:in `block in <class:UsersSignupTest>'

  19/19: [===================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.41513s
19 tests, 48 assertions, 1 failures, 0 errors, 0 skips
```

フォームのアクションを修正。

```/sample_app/app/views/users/new.html.erb
・・・略・・・
    <%= form_for(@user, url: signup_path) do |f| %>
```

画面に表示されたフォーム部のHTMLを確認。
action=/signupになっていることを確認。

```
<form class="new_user" id="new_user" action="/signup" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="SvCd4M/g92PHznf5vZouH+yAykUoH64pHgQdFvQWzp5zqU7P6uZ6jSv0U9552ZD3ffBaI5170L9ZeYZMTXvrpQ==">

      
      
      <label for="user_name">Name</label>
      <input class="form-control" type="text" name="user[name]" id="user_name">
      
      <label for="user_email">Email</label>
      <input class="form-control" type="email" name="user[email]" id="user_email">
      
      <label for="user_password">Password</label>
      <input class="form-control" type="password" name="user[password]" id="user_password">
      
      <label for="user_password_confirmation">Confirmation</label>
      <input class="form-control" type="password" name="user[password_confirmation]" id="user_password_confirmation">
      
      <input type="submit" name="commit" value="Create my account" class="btn btn-primary" data-disable-with="Create my account">
</form>
```

再度テストを実行。
greenになっていることを確認。

```
yokoyan:~/workspace/sample_app (sign-up) $ rails test
Running via Spring preloader in process 3051
Started with run options --seed 16395

  19/19: [===================================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.13927s
19 tests, 48 assertions, 0 failures, 0 errors, 0 skips
```

#おわりに
はじめての投稿で緊張でした。
Markdownで書くのは敷居が高いと思っていましたが、
やってみたら楽しかったです。

これからどんどん情報発信するぞー。