2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】RSpecでのテスト時に詰まったところ~画像の添付、postリクエスト時のパラメーター付加など~

Posted at

はじめに

ここまる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
  • like1createしたうえで、like2buildしてsaveする流れを取っています
  • like2createしない理由は、そうしてしまうと処理がlike2createする時点で止まってしまい、テストしたい内容を確認できないためです

画像の添付の有無でバリデーションが効くかを試したい

# 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)はファクトリで使えるコールバックの一つのようです
  • 今回の場合はpostbuildされた際に、画像ファイルを添付するような動きをしています
  • ちなみに、createbuild + 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側が混同してしまったようでした

おわりに

初学者の自身にとっては一つ一つつまずく点でしたが、テストが通ったときの快感はたまらないものがありました笑

今回は最後にまとめてテストしてしまったせいで無駄に時間を使ってしまいました。
今後はプルリクの前にテストをして問題ないものをマージしていくという流れを取っていきます。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?