RSpecでアップロードされたファイルをつくってテストする

井原(@ihara2525)です。

RSpecでアップロードされたファイルをつくってテストしたい、という場合、以下のようなファイルをshared contextとして作成し、必要な箇所でincludeして使うようにしています。

spec/support/shared_contexts/uploaded_file.rb

include ActionDispatch::TestProcess

RSpec.shared_context 'uploaded file' do
  let(:uploaded_file) do
    uploaded_file = fixture_file_upload('images/ハレアカラ.jpg', 'image/jpeg')
    allow(uploaded_file).to receive(:tempfile).and_return(uploaded_file)
    uploaded_file
  end
end

fixture_file_uploadに渡している実ファイルは、spec/fixtures以下につくってあげれば良いです。この場合だと、spec/fixtures/images/ハレアカラ.jpgですね。 あとは、tempfileが呼ばれたときに自分自身を返すようにしてあげているくらいです。

例えば、Dragonflyでサーバ上に一時的に画像ファイルを保存するメソッドを持つ以下のようなサービスオブジェクトがあった場合、

class UserProfilePhotoUpdating
  def initialize(user, params)
    @user = user
    @params = params
  end

  def retained_image
    app = Dragonfly.app
    uid = app.store(@params[:user_profile_photo][:image].tempfile)
    app.fetch(uid)
  end
end

retained_imageはアップロードされたファイルにアクセスするため、上記のuploaded fileを使っています。

require 'rails_helper'

RSpec.describe UserProfilePhotoUpdating do
  subject { UserProfilePhotoUpdating.new(user, params) }

  let(:user) { FactoryGirl.create(:user) }

  describe '#retained_image' do    
    include_context 'uploaded file'

    let(:params) { { user_profile_photo: { image: uploaded_file } } }

    it 'stores uploaded file and creates the image' do
      expect(subject.retained_image).to be_a(Dragonfly::Job)
    end
  end
end

というわけで、何かのお役に立てば幸いです。