はじめに
ここまる2日かけてRSpecを使ったテストコードを書いていました。
その中で、’この内容をテストしたいけどどう書いたらいいんだろう…?’と思うものがたくさんあったので、まとめておきます。
少し悩んだテスト内容と記述方法
Model Spec
user_idとpost_idのペアにつけている一意性制約のテスト
require 'rails_helper'
RSpec.describe Like, type: :model do
context '同じポストにいいねしようとした場合' do
let!(:user) { create(:user) }
let!(:post) { create(:post) }
let!(:like1) { create(:like, user: user, post: post) }
let!(:like2) { build(:like, user: user, post: post) }
before do
like2.save
end
it 'いいねされない' do
expect(like2).not_to be_valid
expect(like2.errors[:user_id]).to include("has already been taken")
end
end
end
-
like1
をcreate
したうえで、like2
をbuild
してsave
する流れを取っています -
like2
をcreate
しない理由は、そうしてしまうと処理がlike2
をcreate
する時点で止まってしまい、テストしたい内容を確認できないためです
画像の添付の有無でバリデーションが効くかを試したい
# factories/posts.rb
FactoryBot.define do
factory :post do
caption { Faker::Lorem.characters(number: 50) }
association :user
trait :with_image do
after(:build) do |post|
post.images.attach(
io: File.open(Rails.root.join('app/assets/images/arror.png')),
filename: 'arror.png',
content_type: 'image/png'
)
end
end
end
end
# post_spec.rb
require 'rails_helper'
RSpec.describe Post, type: :model do
context '正しい情報が与えられた場合' do
let!(:post) { build(:post, :with_image) }
before do
post.save
end
it '投稿が保存される' do
expect(post).to be_valid
end
end
context '画像が添付されていない場合' do
let!(:post) { build(:post) }
before do
post.save
end
it '投稿が保存さない' do
expect(post).not_to be_valid
expect(post.errors.messages[:images][0]).to eq("can't be blank")
end
end
end
- ポイントは以下の箇所です
-
trait :with_image do after(:build) do |post| post.images.attach( io: File.open(Rails.root.join('app/assets/images/arror.png')), filename: 'arror.png', content_type: 'image/png' ) end end
-
trait
をつかうと、属性やオプションのようなものを定義し、モデルのインスタンス作成時につけたり外したりできます - 今回の場合は
with_image
というtrait
を定義し、画像付きのpostと画像なしのpostをそれぞれテストしています -
after(:build)
はファクトリで使えるコールバックの一つのようです - 今回の場合は
post
がbuild
された際に、画像ファイルを添付するような動きをしています - ちなみに、
create
はbuild
+save
の動きをするようなので、create(:post, :with_image)
でも使えます
Request Spec
postリクエストにパラメーターを付加する方法
post path, params: { model: { key: val } }
具体例
post post_like_path(post_id: test_post.id), params: { like: { post_id: test_post.id } }
- 属性?として
params: { model: { key: val } }
でパラメーターを付加できる - postリクエストを受け取る場合、Controller側でストロングパラメーターを設定していることも多いと多いと思うので、その形式に合わせて書く、とするとわかりやすそうです
postリクエスト時に画像の添付をする方法
context 'ログインしている&&プロフィールが設定されている状態で記事を投稿する場合' do
let!(:image_path) { Rails.root.join('app/assets/images/arror.png') }
let!(:image_file) { fixture_file_upload(image_path, 'image/png') }
describe "post /post" do
it "ポストが作成され、ルートページに遷移する" do
post posts_path, params: { post: { caption: 'hogehoge', images: [image_file] } }
.
.
.
end
end
end
- ActiveStratgeを使う場合にはアップロードの用の処理を別途記載する必要がありそうでした
- 具体的には以下の箇所です
-
let!(:image_path) { Rails.root.join('app/assets/images/arror.png') } let!(:image_file) { fixture_file_upload(image_path, 'image/png') }
-
fixture_file_upload
はテスト時にファイルをアップロードするためのヘルパーメソッドのようです - 第1引数に画像ファイルまでのパス、第2引数にファイル形式を指定します
モデル名がPostのときの注意点…
- なにげに解決に一番時間がかかったのはこれでした…
- 詳細はこちらの記事が大変わかりやすかったです
- 要するに、モデル名を
Post
、テスト時のインスタンス名もpost
にしてしまっていたので、リクエストとしてpostとインスタンスとしてのpost
をRSpec側が混同してしまったようでした
おわりに
初学者の自身にとっては一つ一つつまずく点でしたが、テストが通ったときの快感はたまらないものがありました笑
今回は最後にまとめてテストしてしまったせいで無駄に時間を使ってしまいました。
今後はプルリクの前にテストをして問題ないものをマージしていくという流れを取っていきます。