今や電子メールを持っていて当たり前の時代で、メールを送らないサービスはほとんどありません。
Railsでは、ActionMailerというメールを送る機能が標準で備わっています。
今回はActionMailerを使ったメール送信のテストについて書き方をまとめていきます。
ちなみに、ActionMailerでは同期処理で送るパターンと非同期処理で送るパターンの2種類があるので、2種類を別々にご紹介します。
目次
以下のようなメーラーをサンプルに以降、解説していきます。
class MyAwesomeMailer < ApplicationMailer
def hello_world(email)
mail(to: email, subject: 'This is Test Mailer!')
end
end
先ほどご紹介した通り、ActionMailerを使うとき、同期処理と非同期処理の2種類の送信方法があります。
同期処理をする場合は以下のようにdeliver_now
を呼び出します。
class MailsController < ApplicationController
def send
MyAwesomeMailer.hello_world('test@example.com').deliver_now
end
end
この場合、メール送信が完了するまで、MailsController#send
はクライアントにレスポンスを返しません。
ちょっとしたメールを送りたい場合や、メールを送らないと次に進んではいけない場合はこちらが便利です。
非同期処理の場合は以下のようにdeliver_later
を呼び出します。
class MailsController < ApplicationController
def send_later
MyAwesomeMailer.hello_world('test@example.com').deliver_later
end
end
この場合、メール送信のタスクをキューに貯めて後から処理するので、MailsController#send_later
はクライアントにレスポンスを返したあとで、メールを送信します。
大量のメールを一度に送りたいときや、重いファイルを添付したメールを送りたいときには、ユーザーを待たせることなくストレスフリーな仕様が実現できます。
# もちろんspec/rails_helper.rbに記述してもOK
include ActiveJob::TestHelper
describe 'MailsController' do
context '#send' do
example 'メールが送られる' do
expect {
post mails_path
}.to change { ActionMailer::Base.deliveries.size }.by(1)
end
end
context '#send_later' do
example 'メールが送られる' do
expect {
# perform_enqueued_jobsを利用するにはActiveJob::TestHelperをincludeする必要がある
perform_enqueued_jobs { post mails_path }
}.to change { ActionMailer::Base.deliveries.size }.by(1)
end
end
end
ActionMailerではテスト環境でメールが送られたとき、ActionMailer::Base.deliveries
の中にメールの内容が格納されます。
もし、うまくdeliveriesの中にメールが格納されていない場合は、config/environments/test.rbにdelivery_method :test
の記述があるか確認してみてください。
expect { A }.to change { B }.by( C )
上記のコードは「Aを実行したときBの数値がCだけ増える」という意味です。ここでは、送信済みメールが1つ増えることを確認しています。
もし、N通送る場合は、Cの部分をNにしてあげればOKです。
include ActiveJob::TestHelper
describe 'MailsController' do
context '#send' do
example '件名が正しい' do
post mails_path
last_mail = ActionMailer::Base.deliveries.last
expect(last_mail.subject).to eq 'This is Test Mailer!'
end
end
context '#send_later' do
example '件名が正しい' do
perform_enqueued_jobs do
post mails_path
end
last_mail = ActionMailer::Base.deliveries.last
expect(last_mail.subject).to eq 'This is Test Mailer!'
end
end
end
deliveriesの中から最後に送られたものを取り出してチェックしています。to
やbody
もチェックできるので、確認してみてください。
ActionMailer::Base.deliveries
は自動的にリセットされません。リセットするためにはActionMailer::Base.deliveries.clear
を明示的に記述する必要があります。