※CRUD操作の内、destroyアクションにしか言及しません。
request specでdestroyアクションのテストを行っていて、
userに関連づいたproductを削除してもテストコード内でcountが−1されず、0のままになっていて長い間困っていた。web上で探してみてもいい感じの記事が見つからなかったので今後同じようなエラーに悩まされた人がいた場合に備えて私の解決策を残しておく。
これがエラー文
expected `Product.count` to have changed by -1, but was changed by 0
改善前のソースコード
describe 'DELETE #destroy' do
context 'ログインしているユーザー' do
🌟🌟let(:product_params) do
{ product: {
title: "削除用",
language: "PHP",
detail: "ウオウオの実",
period: "8年",
user: user
}
}
end
subject { delete product_path(product_params) }
it '投稿数が一つ減っている' do
sign_in_as(user)
expect { subject }.to change(Product, :count).by(-1)
end
だが、これだと上記のようなエラーが出てしまう。流れの解説としては、まずlet(:product_params)~内で削除するproductの準備をする。
そしてsubject(繰り返しを避けるために共通化しておく)内でproduct_paramsの削除を行い、
expectでProductの数が1つ減っているかの確認をする。
ここからが改善策
describe 'DELETE #destroy' do
context 'ログインしているユーザー' do
it '投稿数が一つ減っている' do
🌟🌟 product_params = user.products.create(title: "削除用",language:
"PHP",detail: "ウオウオの実",period: "8年",user: user)
sign_in_as(user)
expect{ product_params.destroy }.to change{ Product.count }.by(-1)
end
最初のコードと違う点は、
product_params = user.products.create(title: "削除用",language:
"PHP",detail: "ウオウオの実",period: "8年",user: user)
ここでproduct_paramsを作成している点だ。最初のコードではproductの情報をcreateしていないのに削除(destroty)していたので、それではcountが0のままなのも今となっては理解ができる。
では、productを作成する書き方として、以下のようなコードはどうだろうか?
post products_path, params: product_params
理由はよくわからないが、これでは動かなかった。
今後RSpecでControllerのテストの中で削除するためなど、一時的にデータを保存しておきたい場合はpostで送るのではなく,createを使っていこうと思う。