はじめに
Rails5.2でActive Storageが追加されましたが、まだまだファイルアップロードにCarrierWaveを使われている方も多いと思います。
最近ファイルアップロードを必須とするモデルを作ったところ、テストの際にいちいちバリデーションにひっかかって面倒だったので今回の方法を調べました。
基本的には以下のCarrierWaveのwikiに書いてある通りなんですが、少しハマったので記事にしたいと思います。
バージョン
- Rails 5.2.1
- CarrierWave 1.2.3
CarrierWaveの設定
CarrierWave.configure do |config|
config.root = "/var/www/app"
config.cache_dir = "/var/www/app/uploads/tmp"
end
class UserIconUploader < CarrierWave::Uploader::Base
## 省略 ##
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
テスト用の設定
carrierwave_helperを作成
CarrierWaveのwikiからコピってきます。
require 'fileutils'
# Carrierwave setup and teardown
carrierwave_template = Rails.root.join('test','fixtures','files')
carrierwave_root = Rails.root.join('test','support','carrierwave')
# Carrierwave configuration is set here instead of in initializer
CarrierWave.configure do |config|
config.root = carrierwave_root
config.enable_processing = false
config.storage = :file
config.cache_dir = Rails.root.join('test','support','carrierwave','carrierwave_cache')
end
# And copy carrierwave template in
#puts "Copying\n #{carrierwave_template.join('uploads').to_s} to\n #{carrierwave_root.to_s}"
FileUtils.cp_r carrierwave_template.join('uploads'), carrierwave_root
at_exit do
#puts "Removing carrierwave test directories:"
Dir.glob(carrierwave_root.join('*')).each do |dir|
#puts " #{dir}"
FileUtils.remove_entry(dir)
end
end
コードを見れば分かると思いますが、やってることはこんな感じです。
- CarrierWaveの対象ディレクトリを
test/support/carrierwave
に変更 - テスト開始時に
test/fixtures/files/uploads
をコピーして、test/support/carrierwave/uploads
を作成 - テスト終了時に
test/support/carrierwave
以下のディレクトリを全て削除
作成したらtest_helperでrequireします。
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'carrierwave_helper' # 追加
### 省略 ###
テストデータの作成
test/fixtures/files/uploadsにテスト用のファイルを用意します。
また、test/support/carrierwaveディレクトリも作成しておきます。
$ tree ${RAILS_ROOT}/test/
test/
## 省略 ##
├── fixtures
│ ├── files
│ │ └── uploads
│ │ └── user
│ │ └── icon
│ │ ├── 1
│ │ │ └── test1.png
│ │ └── 2
│ │ └── test2.png
│ └── users.yml
├── support
│ └── carrierwave
├── carrierwave_helper.rb
└── test_helper.rb
users.ymlでは、ファイル名を指定するだけでOKです。
user_1:
id: 1
name: ユーザー1
email: test_user1@example.com
icon: test1.png
user_2:
id: 2
name: ユーザー2
email: test_user2@example.com
icon: test2.png
以上でCarrierWaveを使っているモデルのfixtureが完成です。
最後に
CarrierWaveのwikiにはMinitest用の設定と書いてあるんですが、RSpecはfixtureを使わないんですかね?
自分はMintestでしかテストを書いたことがないので、どなたかコメント頂けると嬉しいです。