紙一重の積み重ね

35歳のエンジニアがなれる最高の自分を目指して、学んだことをこつこつ情報発信するブログです。

【7章】Ruby on Railsチュートリアル演習まとめ&解答例【7.3.4 失敗時のテスト】

はじめに

Ruby on Rails チュートリアル実例を使ってRailsを学ぼう 第4版の 7章 7.3.4 失敗時のテストの演習まとめ&解答例です。

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

7.3.4 失敗時のテスト

演習1

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

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

  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ファイルを追加。

・・・略・・・
  post '/signup', to: 'users#create'
・・・略・・・
    <%= 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 ユーザーを作成するアクション

現在のテストケース。

・・・略・・・
    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に修正。

・・・略・・・
    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の状態に戻す。

・・・略・・・
    <%= 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>

テストコードを追加。

  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

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

・・・略・・・
    <%= 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で書くのは敷居が高いと思っていましたが、 やってみたら楽しかったです。

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