やりたかった事
HogeMailer
があり、HogeDelivery
のインスタンスメソッド(send_email
)内でHogeMailer
を使ってメールを飛ばしていました。
私は今HogeDelivery
のモデルテストを書いていたのでsend_email
のテストを書こうとしました。しかし、ActionMailer::Base.deliveries.count
等は使えません(なぜかは知らないので聞かないで) ので、実際にメールが送信できたのか別手段でテストしようと思ったのが始まり。
前提
class HogeMalier < ActionMailer::Base def send_hoge mail(to: params[:to], template: params[:template],......) end end
class HogeDelivery < ActiveRecord::Base def send_email # 色々処理する # Userクラスからuserを引っ張ったり ... HogeMailer.with(toとかsubjectとか).send_hoge.deliver_now # ここがdeliver_laterの場合もある end end
deliver_later
の場合
deliver_later
はActiveJob
を利用して、非同期的にメールを送信します。have_enqueued_job
でメール送信ジョブが登録されたことを確認できます。同時にenqueued_jobs
からはその情報を取得することができるので、中身をテストしたい場合はこちらを使います。
describe 'HogeDelivery', type: :model do subject{send_mail}(hoge_delivery.send_email) # 引数に送信先の情報を渡す実装ならここ変更 let!(:hoge_delivery){create(:hoge_delivery)} let!(:user){create(:user)} it 'enqueue a job' do expect { send_mail }.to have_enqueued_job.on_queue("mailers") # ジョブが登録される end it 'use user name for "to" value' do send_mail expect(enqueued_jobs[0][:args][3]["to"]).to eq user.name # ジョブから値を引っ張ってくる end end
deliver_now
の場合
deliver_now
はActiveJob
を使用せずに同期的に送信するため、上の方法では送信できているのか確認できません。
しかし、よくよく考えるとこのHogeDelivery
モデルテストで担保すべきは、deliver_now
がしっかり呼ばれることです。deliver_now
はあくまでHogeMailer
の責務として考えた場合、スタブを利用してメソッドが呼ばれることのみをテストすれば良さそうです。
describe 'HogeDelivery', type: :model do subject{send_mail}(hoge_delivery.send_email) # 引数に送信先の情報を渡す実装ならここ変更 let!(:hoge_delivery){create(:hoge_delivery)} let!(:user){create(:user)} it "call #deliver_later" do message_delivery = instance_double(ActionMailer::MessageDelivery) allow(HogeMailer).to receive_message_chain(:with, :send_hoge). with(to: to, subject: ..とか色々).with(no_args). and_return(message_delivery) expect(message_delivery).to receive(:deliver_later send_mail end end
しかし、send_email
内ではUser
クラスから情報を引き出してきたりと、テストすべき部分はあります。そのため、deliver_later
を使っているのであれば、上のような期待した値が格納されているかテストするのも、大事かと思います。
余談
スタブは、メソッドを実行させずに欲しい値を取得するもの、モックは指定のメソッドが実行されたかどうかをチェックするためな感じだそうです。
スタブはallow
、モックはexpect
。まぁ詳しくは参考サイトを見てみてください。