RSpecでActionMailerのメソッドが呼び出されるテストを書く

井原(@ihara2525)です。

RSpecでActionMailerのdeliver_later!が呼び出されることをテストするコードを書いてみます。

コメントがあったときにメールで通知するサービスオブジェクトをつくり、それは中でActionMailerのdeliver_later!等を呼び出しているとします。こんな感じ。

app/services/comment_notification.rb

class CommentNotification
  def initialize(comment)
    CommentNotificationMailer.notify(comment).deliver_later!
  end
end

このサービスオブジェクトをnewしたときに、これらのメソッドが呼び出されることを保証するRSpecのテストを書こうとしてみました。

spec/services/comment_notification_spec.rb

require 'rails_helper'

RSpec.describe CommentNotification do
  describe 'new' do
    let(:blog) { FactoryGirl.build_stubbed(:blog) }
    let(:comment) { FactoryGirl.build_stubbed(:comment, commentable: blog) }
    let(:mailer) { double('mailer', deliver_later!: true) }

    it 'calls mailer methods' do
      expect(CommentNotificationMailer).to receive(:notify).with(comment).and_return(mailer)
      expect(mailer).to receive(:deliver_later!)
      CommentNotification.new(comment)
    end
  end
end

テストの中身を見てみると、

expect(CommentNotificationMailer).to receive(:notify).with(comment).and_return(mailer)

で、CommentNotificationMailerのnotifyメソッドがcommentを引数に呼び出されてmailerを返し、

expect(mailer).to receive(:deliver_later!)

で、そのmailerがdeliver_later!を呼び出されることをテストする、みたいな。

expect(CommentNotificationMailer).to recieve_message_chain(:notify, :deliver_later!)

メソッドチェインのテストを書くこともできたのですが、commentを引数にnotifyが呼び出されていることをテストしておきたかったので、このようなかたちになりました。

もっと良いやり方があるのかな〜。