はじめに
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で書くのは敷居が高いと思っていましたが、 やってみたら楽しかったです。
これからどんどん情報発信するぞー。