概要
「Railsチュートリアル 第13章 ユーザーのマイクロポスト - マイクロポストを操作する - 演習「フィード画面のマイクロポストをテストする」より、演習1番目の内容です。Railsチュートリアル本文には以下のようにあります。
リスト 13.55で示した4つのコメント (「無効な送信」など) のそれぞれに対して、テストが正しく動いているか確認してみましょう。具体的には、対応するアプリケーション側のコードをコメントアウトし、テストが
red
になることを確認し、元に戻すとgreen
になることを確認してみましょう。
なお、「それぞれの確認で変更したソースコードは、確認が終わったら変更前の状態に戻すこと」を前提とします。
無効なマイクロポストを受け付けてしまう場合
無効なマイクロポストを受け付けてしまう例としては、「Micropostモデルのバリデーションが正常に機能していない場合」が想定できます。具体的には、「Micropostモデルのcontent
属性に対するバリデーションが動作していない場合」です。当該バリデーションに関するソースコードをapp/models/micropost.rb
からコメントアウトしてみます。
class Micropost < ApplicationRecord
belongs_to :user
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
- validates :content, presence: true, length: { maximum: 140 }
+ # validates :content, presence: true, length: { maximum: 140 }
end
この状態で、test/integration/microposts_interface_test.rb
を対象にテストを実行してみましょう。
# rails test test/integration/microposts_interface_test.rb
Running via Spring preloader in process 513
Started with run options --seed 28697
FAIL["test_micropost_interface", MicropostsInterfaceTest, 4.152912300000025]
test_micropost_interface#MicropostsInterfaceTest (4.15s)
"Micropost.count" didn't change by 0.
Expected: 38
Actual: 39
test/integration/microposts_interface_test.rb:18:in `block in <class:MicropostsInterfaceTest>'
1/1: [===================================] 100% Time: 00:00:04, Time: 00:00:04
Finished in 4.15470s
1 tests, 7 assertions, 1 failures, 0 errors, 0 skips
"Micropost.count" didn't change by 0.
Expected: 38
Actual: 39
上記は「(当該テストテストコードの時点で変化してはならない)Micropost.count
の値が変化してしまっている」という趣旨のメッセージですね。
また、私の環境では、test/integration/microposts_interface_test.rb
の17行目から20行目のソースコードは以下のようになっています。
# 無効な送信
assert_no_difference 'Micropost.count' do
post microposts_path, params: { micropost: { content: "" } }
end
想定通りの形でテストが失敗したということですね。
有効なマイクロポストが受け付けられない場合
逆に「無効なマイクロポストは受け付けられないが、有効なマイクロポストが受け付けられない」という場合です。
例えば「Strong Parameters機能の利用に際し、受け入れる属性の名前を間違えている」という場合は、このケースに該当するはずです。というわけで、app/controllers/microposts_controller.rb
を以下のように変更した上で保存します。
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
...略
private
def micropost_params
- params.require(:micropost).permit(:content)
+ params.require(:micropost).permit(:id)
end
この状態で、test/integration/microposts_interface_test.rb
を対象にテストを実行してみましょう。
# rails test test/integration/microposts_interface_test.rb
Running via Spring preloader in process 526
Started with run options --seed 19620
FAIL["test_micropost_interface", MicropostsInterfaceTest, 3.3941545999987284]
test_micropost_interface#MicropostsInterfaceTest (3.39s)
"Micropost.count" didn't change by 1.
Expected: 39
Actual: 38
test/integration/microposts_interface_test.rb:24:in `block in <class:MicropostsInterfaceTest>'
1/1: [===================================] 100% Time: 00:00:03, Time: 00:00:03
Finished in 3.40014s
1 tests, 9 assertions, 1 failures, 0 errors, 0 skips
"Micropost.count" didn't change by 1.
Expected: 39
Actual: 38
上記は「(当該テストテストコードの時点で1増えていなければならない)Micropost.count
の値が1増えていない」という趣旨のメッセージですね。
また、私の環境では、test/integration/microposts_interface_test.rb
の22行目から26行目のソースコードは以下のようになっています。
# 有効な送信
content = "This micropost really ties the room together"
assert_difference 'Micropost.count', 1 do
post microposts_path, params: { micropost: { content: content } }
end
想定通りの形でテストが失敗したということですね。
投稿が削除されない場合
「投稿が削除されない」という事態が発生する原因はいくつか考えられます。
マイクロポストをRDBから削除する処理の実装が抜けた場合
マイクロポストをRDBから削除する処理の実装が抜けた場合について確認してみましょう。一番単純なケースですね。
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: [:destroy]
...略
def destroy
- @micropost.destroy
+ # @micropost.destroy
flash[:success] = "Micropost deleted"
redirect_back(fallback_location: root_url)
end
private
...略
end
上記変更を適用した状態で、test/integration/microposts_interface_test.rb
に対してテストを実行してみましょう。
# rails test test/integration/microposts_interface_test.rb
Running via Spring preloader in process 552
Started with run options --seed 40696
FAIL["test_micropost_interface", MicropostsInterfaceTest, 3.7064526000031037]
test_micropost_interface#MicropostsInterfaceTest (3.71s)
"Micropost.count" didn't change by -1.
Expected: 38
Actual: 39
test/integration/microposts_interface_test.rb:33:in `block in <class:MicropostsInterfaceTest>'
1/1: [===================================] 100% Time: 00:00:03, Time: 00:00:03
Finished in 3.71107s
1 tests, 14 assertions, 1 failures, 0 errors, 0 skips
"Micropost.count" didn't change by -1.
Expected: 38
Actual: 39
上記は「(当該テストテストコードの時点で1減っていなければならない)Micropost.count
の値が1減っていない」という趣旨のメッセージですね。
また、私の環境では、test/integration/microposts_interface_test.rb
の30行目から35行目のソースコードは以下のようになっています。
# 投稿を削除する
assert_select 'a', text: 'delete'
first_micropost = @user.microposts.paginate(page: 1).first
assert_difference 'Micropost.count', -1 do
delete micropost_path(first_micropost)
end
想定通りの形でテストが失敗したということですね。
Beforeフィルターの実装内容に誤りがあった場合
今回実装したMicropostsコントローラーでは、マイクロポストの削除に際し、logged_in_user
とcorrect_user
という2つのBeforeフィルターが適用されます。その実装内容に誤りがあった場合も、マイクロポストの削除はうまくいかないはずです。
今回は、correct_user
フィルターの実装内容を、意図的に誤ったものにしてみます。
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: [:destroy]
...略
def destroy
@micropost.destroy
flash[:success] = "Micropost deleted"
redirect_back(fallback_location: root_url)
end
private
...略
def correct_user
@micropost = current_user.microposts.find_by(id: params[:id])
- redirect_to root_url if @micropost.nil?
+ redirect_to root_url unless @micropost.nil?
end
end
上記変更を適用した状態で、test/integration/microposts_interface_test.rb
に対してテストを実行してみましょう。
# rails test test/integration/microposts_interface_test.rb
Running via Spring preloader in process 578
Started with run options --seed 23555
FAIL["test_micropost_interface", MicropostsInterfaceTest, 4.179720099997212]
test_micropost_interface#MicropostsInterfaceTest (4.18s)
"Micropost.count" didn't change by -1.
Expected: 38
Actual: 39
test/integration/microposts_interface_test.rb:33:in `block in <class:MicropostsInterfaceTest>'
1/1: [===================================] 100% Time: 00:00:04, Time: 00:00:04
Finished in 4.20035s
1 tests, 14 assertions, 1 failures, 0 errors, 0 skips
前述「マイクロポストをRDBから削除する処理が抜けた場合」と同様の形でテストが失敗しています。
自身のページにマイクロポストの削除リンクが表示されない場合
<li id="micropost-<%= micropost.id %>">
<%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
<span class="content"><%= micropost.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
- <% if current_user?(micropost.user) %>
+ <%# <% if current_user?(micropost.user) %> %>
- <%= link_to "delete", micropost, method: :delete, data: { confirm: "You sure?" } %>
+ <%# <%= link_to "delete", micropost, method: :delete, data: { confirm: "You sure?" } %> %>
- <% end %>
+ <%# <% end %> %>
</span>
</li>
上記変更を適用した状態で、test/integration/microposts_interface_test.rb
に対してテストを実行してみましょう。
# rails test test/integration/microposts_interface_test.rb
Running via Spring preloader in process 617
Started with run options --seed 35207
FAIL["test_micropost_interface", MicropostsInterfaceTest, 3.800804300000891]
test_micropost_interface#MicropostsInterfaceTest (3.80s)
<delete> expected but was
<sample app>..
Expected 0 to be >= 1.
test/integration/microposts_interface_test.rb:31:in `block in <class:MicropostsInterfaceTest>'
1/1: [===================================] 100% Time: 00:00:03, Time: 00:00:03
Finished in 3.81553s
1 tests, 13 assertions, 1 failures, 0 errors, 0 skips
<delete> expected but was
<sample app>..
Expected 0 to be >= 1.
「deleteというリンクテキストのa要素
が、1つ以上存在するはずなのに1つも存在しない」という趣旨のメッセージですね。
また、私の環境では、test/integration/microposts_interface_test.rb
の30行目から31行目のソースコードは以下のようになっています。
# 投稿を削除する
assert_select 'a', text: 'delete'
想定通りの形でテストが失敗したということですね。
違うユーザーのページにマイクロポストの削除リンクが表示される場合
<li id="micropost-<%= micropost.id %>">
<%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
<span class="content"><%= micropost.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
- <% if current_user?(micropost.user) %>
+ <%# <% if current_user?(micropost.user) %> %>
+ <%= link_to "delete", micropost, method: :delete, data: { confirm: "You sure?" } %>
- <% end %>
+ <%# <% end %> %>
</span>
</li>
上記変更を適用した状態で、test/integration/microposts_interface_test.rb
に対してテストを実行してみましょう。
# rails test test/integration/microposts_interface_test.rb
Running via Spring preloader in process 604
Started with run options --seed 24198
FAIL["test_micropost_interface", MicropostsInterfaceTest, 3.710591699997167]
test_micropost_interface#MicropostsInterfaceTest (3.71s)
Expected exactly 0 elements matching "a", found 2..
Expected: 0
Actual: 2
test/integration/microposts_interface_test.rb:38:in `block in <class:MicropostsInterfaceTest>'
1/1: [===================================] 100% Time: 00:00:03, Time: 00:00:03
Finished in 3.72132s
1 tests, 15 assertions, 1 failures, 0 errors, 0 skips
Expected exactly 0 elements matching "a", found 2..
Expected: 0
Actual: 2
「1つも存在しないはずの(deleteというリンクテキストの)a
要素が2つ存在する」というメッセージが表示されています。
また、私の環境では、test/integration/microposts_interface_test.rb
の36行目から38行目のソースコードは以下のようになっています。
# 違うユーザーのプロフィールにアクセス(削除リンクがないことの確認)
get user_path(users(:mkirisame))
assert_select 'a', text: 'delete', count: 0
想定通りの形でテストが失敗したということですね。