概要
Rspecのテストで、値を更新や削除などのデータ変更が加えられた際に
テストの記述の仕方について多少手間取ったので備忘録としてアウトプットします。
環境
Ruby '3.0.1'
rails '6.1.4'
rspec-rails '5.0.2'
テストコード
前提
今回のテストはpostコントローラーにdeleteリクエストを送った際に、
該当する投稿データが削除されるといったテストを想定します。
なお、実際のコードについては説明に重点を置くため簡易的に表記します。
controllers/posts_controller.rb
class PostsController < ApplicationController
def destroy
post = Post.find(params[:id]) # 左記のコードでは誰の投稿でも削除が可能になってしますので、
post.destory # ユーザー自身の投稿のみ削除可能にするための条件分岐等を行ったほうが良い
end
end
spec/requests/posts_spec.rb (失敗例)
RSpec.describe "Posts", type: :request do
describe 'DELETE /destroy' do
# 以降はFactory_Botで設定済みと仮定
# UserモデルとPostモデルの関連付けも設定済みと仮定
let!(:user) { create(:user) } # テストユーザーを生成
let(:post_params) { { content: 'example_content' } }
let!(:post) { user.posts.create(post_params) } # userの投稿データを作成
before do
delete posts_path(post) # 投稿データを削除するリクエストを送る
end
it 'userの投稿が削除される' do
expect(user.posts).not_to include post #左記のように記載すると失敗する
end
end
end
spec/requests/posts_spec.rb (成功例)
RSpec.describe "Posts", type: :request do
describe 'DELETE /destroy' do
# 以降はFactory_Botで設定済みと仮定
# UserモデルとPostモデルの関連付けも設定済みと仮定
let!(:user) { create(:user) } # テストユーザーを生成
let(:post_params) { { content: 'example_content' } }
let!(:post) { user.posts.create(post_params) } # userの投稿データを作成
before do
delete posts_path(post) # 投稿データを削除するリクエストを送る
end
it 'userの投稿が削除される' do
expect(user.posts.reload).not_to include post #修正
end
end
end
失敗の原因
失敗例で記載したexpect内のuser.posts
は最初のlet!
に定義したユーザーのデータが格納されてしまっているので
__deleteリクエストを送る前のデータ__を参照していることになります。
したがって成功例で示したようにuser.posts.reload
とすることによって
user.posts
の__データを更新__してあげなければならなかったようです。