これを参考にしてCarrierWaveを使った画像アップロード機能を実装してみた。
Rails 超お手軽な画像アップローダー CarrierWave の使い方 | Workabroad.jp
↑のサイトではCapybaraを使ったインテグレーションテストの書き方は載っているけど、コントローラのテスト方法が載っていなかったのでちょっとだけ詰まった。
言い換えると、今回はファイルを添付してアップロードするフォームのテストを書くというのと同義。
サンプル
フォーム
Userモデルには名前とプロフィール画像があって、更新フォームで名前とか画像をセットできることにする。
= form_for(@user, html:{ method: :put, role: "form" }) do |f|
.form-group
= f.label :image, "プロフィール画像"
= f.file_field :image, class:"form-control"
.form-group
= f.label :name, "名前"
= f.text_field :name, :autofocus => true, class:"form-control"
こんなフォーム。
コントローラ
class UsersController < ApplicationController
def edit
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
redirect_to edit_user_url(@user)
else
render :edit
end
end
private
def user_params
params.require(:user).permit(:name, :image)
end
end
updateメソッドがあって、name
とimage
を更新できるようにpermit
している。
テスト要画像の用意
#{Rails.root}/spec/fixtures
にテスト要のファイルを配置する。今回は画像ファイルなので、適当なファイルをsample.png
という名前で置いておくことにした。
コントローラのテスト
RSpec.describe UsersController, :type => :controller do
describe "PUT update" do
before do
# テストユーザーでログインしておく
@user = login_user
# 先ほどのファイル
@file = fixture_file_upload("sample.png", "image/png", true)
end
it "アップロードが正常に終わり、@user.image?がtrueを返す" do
put 'update', id: @user.id, user: {
id: @user.id, name: "あたらしいなまえ", image: @file
}
expect(@user).to be_image
end
end
end
fixture_file_upload
でfixtures
ディレクトリに置いたファイルをロードできる。そして、コントローラのupdate
へのPUTリクエストをファイルを含めて呼び出すことでアップロードの完了を確認している。
最後のこの部分
expect(@user).to be_image
が直感的ではないけど、RSpecのルールに従って書くとそうなるというだけで、↓のように書いても問題はない。
expect(@user.image?).to eq(true)
fixture_file_upload
ちなみにfixture_file_upload
っていうメソッドはActionPack
の中で定義されていて、見たところファイルアップロードのテストに使うRack::Test::UploadedFile
を少し便利に使うために見える。
# actionpack-4.1.0/lib/action_dispatch/testing/test_process.rb
module ActionDispatch
module TestProcess
def fixture_file_upload(path, mime_type = nil, binary = false)
if self.class.respond_to?(:fixture_path) && self.class.fixture_path
path = File.join(self.class.fixture_path, path)
end
Rack::Test::UploadedFile.new(path, mime_type, binary)
end
end
end