前提
メール送信処理はすべてdeliver_now
で書いていましたが、処理が重過ぎてタイムアウトするのでdeliver_later
に書き直しました。
結果rspecが軒並み死にました。FFF...
まぁ、そのままではうまくいかんだろうなという予感はしていました。
ということで、rspecの書き方を検討します。
deliver_laterのrspecとして有効そうなこと
deliver_later
はActiveJob
の処理なので、ActiveJob
に近いテストを書くことはできそうです。
- jobの登録有無
- jobの内容
あとは、メール送信処理を即時にすれば、メールの内容などのテストも可能です。
deliver_later
のテストは正直rails側で担保されていると思うので、deliver_laterを即時に変えるテストは有効かと思ってます。
意外と、deliver_later用!っていうrspecは用意されていないようです。調べ方が悪いかもしれないので、ありましたら教えていただきたいです…。mm
modelのテストをjobの登録の確認。
controllerのテストは即時でメールを送信して、メールの内容を確認する。
という役割でテストを書きました。model, controllerで担保するテストの切り分けが未だにわかっていないです。
一応、メールの送信と内容の確認は統合テストに近いのでcontrollerで担保するのが良いかなと考えた結果です。
job登録と即時への変更のテストをmodelとcontrollerで二重で書いてもよいのですが、すでにrspecはほとんど出来上がっており、deliver_later
に変えたことによる影響範囲は莫大だったので止めました。
というかこれだけの変更でもかなり骨が折れました。はじめからdeliver_later
にしておけばよかった。
実際に書いたrspec
同期処理をrspecで使うために以下を追記
ActiveJob::Base.queue_adapter = :test
modelのテストは、jobの登録確認なので以下のように書きました。
Mailerのactionで登録されるようです。
context "trueの場合" do
it "メールのjobが登録される" do
expect {
test.hoge_method(true)
}.to have_enqueued_mail(HogeMailer, :send_mail)
end
end
context "falseの場合" do
it "メールのjobが登録されない" do
expect {
test.hoge_method(false)
}.not_to have_enqueued_mail(HogeMailer, :send_mail)
end
end
controllerのテストは、即時実行に変更しました。
beforeでperform_enqueued_jobs
囲うと、即時で実行してくれました。
requestsの今までのテストを全部これで囲いました(戦慄)。
context "postした場合" do
after { ActionMailer::Base.deliveries.clear }
before do
perform_enqueued_jobs do
post "/users/send_mail"
end
end
it "メールが送信される" do
mailer = ActionMailer::Base.deliveries[0]
expect(mailer).not_to eq nil
expect(mailer.to[0]).to eq "test@dev.hogehoge.jp"
end
end
これでrspecはオールグリーンになりました〜!
その他
enqueued_jobs[0][:args]
でもjobに登録された値を取ってきて内容に関してのテストができそうでした。
が、私の環境だとbccあたりしか入っておらず、paramsでmailerのactionに渡したものしか入ってないのかも?と思ってます。ここの処理が怪しいので調べてわかったことがあれば追記しようと思います…。