LoginSignup
24
27

More than 3 years have passed since last update.

Rails6のActionMailer機能をRSpecでテストする方法

Last updated at Posted at 2020-05-06

はじめに

皆様、こんにちは!
佐久間まゆちゃんのプロデューサーの@hiroki_tanakaです。

私は現在、Railsを使用してメール送信機能を持つシステムを構築しているのですが、
Railsの持つActionMailer機能のRSpecでのテスト実装を少し調べたので紹介させて下さい。

記事の流れとしては、最初に利用環境とActionMailerを使うための下準備に触れ、
その後に実際のActionMailer側のコードとRSpecのコードを記載致します。

利用環境

Ruby 2.6.6
Rails 6.0.2
RSpec 3.9.1

下準備

今回はmailgunをESP(Email Service Provider)として、メール送信を行います。
そのため、mailgunで行った設定をdevelopment.rbに記載をして、rails側でmailgunを使用出来るように設定をします。
ActionMailerのRSpecテストだけ行う場合は本設定は不要ですが、メール送信機能を通常のアプリケーション側から実行する場合は必要です。

development.rb
  config.action_mailer.delivery_method = :smtp
  ActionMailer::Base.smtp_settings = {
    user_name: 'address@domain',
    password: 'password',
    domain: 'domain',
    address: 'smtp.mailgun.org',
    port: 587,
    authentication: :plain,
    enable_starttls_auto: true
  }

次に、mailerとspecファイルを作成します。
下記のrails generateコマンドを実行すれば、TestMailerクラスと紐づくSpecファイルが作成されます。

$ rails g mailer TestMailer

最後に、config/environments/test.rbを開き、
下記のように設定されていることを確認します。
下記のように設定されていると、ActionMailerのテストで実際にメールが送信されずにテストモードで動作します。

test.rb
config.action_mailer.delivery_method = :test

ActionMailer

Mailerクラスにはメール送信のためのコードを記載していきます。

test_mailer.rb
class TestMailer < ApplicationMailer
  def send_mail
      mail_info = {
        to: 'hoge.from@test.com',
        from: 'fuga.to@test.com',
        from_display_name: 'ほげ商事',
        subject: 'ほげ商事の田中太郎です',
        body: '本メールはほげ商事の田中太郎からのテストメールです。'
      }

    from = Mail::Address.new mail_info['from']
    from.display_name = mail_info['from_display_name']

    mail(subject: mail_info['subject'], from: from.format, to: mail_info['to']) do |format|
      format.text { render plain: mail_info['body'] }
    end

  end
end

TestMailerApplicationMailerというActionMailerの基底クラスを継承しています。
その中にメール送信を行うsend_mailという関数を定義します。
mail_infoというハッシュを作成し、メール送信に必要な情報を定義します。
(from_display_nameというのはメール受診時に送信者欄に表示される名前です。)

次に、mail gemのMail::Address.newを使用して、from及びdisplay_nameをActionMailerで使用する型に変換します。
そして、最後のmailメソッドでsubject(メールタイトル)・from(送信元)・to(送信先)を指定します。
formatはHTMLメール形式かプレーンテキスト形式か指定できます。
今回はプレーンテキスト形式で送信するためrender plainとして、本文を設定しています。

以上でActionMailer側のコードは完成です。
下記のコマンド実行すれば、メール送信がされます。

$ rails c
[1] pry(main)> TestMailer.send_mail.deliver

RSpec

TestMailerのテストコードを記載していきます。

test_mailer_spec.rb
require 'rails_helper'

describe TestMailer do

  describe '#send_mail' do
    subject(:mail) do
      described_class.send_mail.deliver_now
      ActionMailer::Base.deliveries.last
    end

    context 'when send_mail' do
      it { expect(mail.from.first).to eq('hoge.from@test.com') }
      it { expect(mail.to.first).to eq('fuga.to@test.com') }
      it { expect(mail.subject).to eq('ほげ商事の田中太郎です') }
      it { expect(mail.body).to match(/本メールはほげ商事の田中太郎からのテストメールです。/) }
    end
  end
end

subject(:mail)で最初のdescribeで宣言されたクラス(今回はTestMailer)のsend_mailを実行することを定義しています。
次のActionMailer::Base.deliveries.lastは最後に送信されたメールの情報を返却します。
そのため、このmailはメール送信処理を行い、値として送信したメールの情報を保持します。

context内のitでは、まずsubjectで定義したmailを呼び出し、メールの送信元/送信先のfrom/toをチェックしています。
mail.to.firstmail.from.firstとしている理由は、mailの戻り値内のfrom/toの情報が
[hoge.from@test.com]/[fuga.to@test.com]と配列になっているためです。
(これはメールの送信元・送信先は複数存在することがあるためです。)

その後、メールタイトルであるsubjectと本文であるbodyを比較します。
bodyは本文以外の情報(encodingなど)も含まれるため、eq matcherではなくmatch matcherを使用します。

以上でRSpecの作成は完了です。コマンドラインからRSpecを実行すれば、正常にパスします。
これでActionMailerと紐づくRSpecのどちらも完成しました。

おわりに

実装を始める前はメール送信機能やそのRSpecが難しく感じましたが、
実際に書いてみると非常に簡単かつ便利にメール送信が出来ました。

参考サイト

ActionMailerのメール送信テストをRSpecで行う

24
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
27