web-dev-qa-db-ja.com

Rails-テストでActionMailerが特定のメールを送信する方法

現在、私のテストでは、電子メールが送信されるためにキューに入れられているかどうかをテストするためにこのようなことをしています

assert_difference('ActionMailer::Base.deliveries.size', 1) do       
  get :create_from_spreedly, {:user_id => @logged_in_user.id}
end

しかし、コントローラーアクションが2つの異なる電子メールを送信できる場合、つまり、サインアップがうまくいくとユーザーに1つ、何かがうまくいかなかった場合は管理者に通知する-実際に送信されたものをテストするにはどうすればよいですか?上記のコードは関係なく渡されます。

45
robodisco

テスト中にActionMailerを使用する場合、すべてのメールはdeliveriesという大きな配列に入れられます。基本的に何をしているのか(ほとんどの場合は十分です)は、配列内に電子メールが存在するかどうかを確認することです。しかし、特定の電子メールを特に確認したい場合は、実際に配列に保存されているものを知る必要があります。幸いなことに、電子メール自体が保存されているため、配列を反復処理して各電子メールを確認できます。

ActionMailer :: Base を参照して、使用可能な構成メソッドを確認してください。この構成メソッドを使用して、配列に存在する電子メールを判別できます。あなたのケースに最も適した方法のいくつかはおそらく

  • recipients:1つ以上のメールアドレスを取得します。これらのアドレスは、メールの配信先です。 To:ヘッダーを設定します。
  • subject:メールの件名。 Subject:ヘッダーを設定します。
27
Veger

Rails 3 ActionMailer :: Base.deliveriesはMail :: Messageの配列です。 メールドキュメンテーション から:

#  mail['from'] = '[email protected]'
#  mail[:to]    = '[email protected]'
#  mail.subject 'This is a test email'
#  mail.body    = 'This is a body'
# 
#  mail.to_s #=> "From: [email protected]\r\nTo: you@...

それからあなたのメールの統合を簡単にテストできるはずです

mail = ActionMailer::Base.deliveries.last

assert_equal '[email protected]', mail['from'].to_s

assert_equal '[email protected]', mail['to'].to_s
76
todd

現在のRspec構文を使用して、次を使用することになりました。

last_email = ActionMailer::Base.deliveries.last
expect(last_email.to).to eq ['[email protected]']
expect(last_email.subject).to have_content 'Welcome'

テストのコンテキストは、サインアップ後にウェルカムメールがユーザーに送信されることを確認したい機能仕様でした。

18
Neal

テストフレームワーク shoulda には、送信された電子メールに関する特定の条件をアサートできる優れたヘルパーがあります。はい、ActionMailer.deliveriesを使用して自分で実行できますが、shouldaはすべてを1つの小さなブロックにまとめます

3
RyanWilcox

少し遅れましたが、他の人に役立つかもしれません:

Email-spec 、Rspec/MinitestマッチャーとCucumberステップのコレクションを使用できます。

2
guapolo

これが、私が見つけた最善の方法です。

1) アクションメーラーコールバック プラグインを含めます:

_script/plugin install git://github.com/AnthonyCaliendo/action_mailer_callbacks.git
_

プラグインの主な機能は実際には使用していませんが、電子メールの送信に使用された方法を把握できるという素晴らしい機能を提供します。

2)これで、test_helper.rbに次のようなメソッドを追加できます。

_  def assert_sent(method_name)
    assert sent_num_times(method_name) > 0
  end

  def assert_not_sent(method_name)
    assert sent_num_times(method_name) == 0
  end

  def assert_sent_once(method_name)
    assert sent_num_times(method_name) == 1
  end

  def sent_num_times(method_name)
    count = 0
    @emails.each do |email|
      count += 1 if method_name == email.instance_variable_get("@method_name")
    end
    count
  end
_

3)これで、次のような甘いテストを書くことができます:

_require 'test_helper'
class MailingTest < ActionController::IntegrationTest

  def setup
    @emails = ActionMailer::Base.deliveries
    @emails.clear
  end

  test "should send a mailing" do
    assert_difference "Mailing.count", 1 do
      feeds(:feed1).generate_mailing
    end

    assert_sent_once "broadcast"
    assert_not_sent "failed_mailing"
  end
end
_

ここで、「broadcast」と「mailing_failed」は、ActionMailer :: Baseクラスのメソッドの名前です。これらは、通常Mailer.deliver_broadcast(some_data)またはMailer.deliver_failed_mailing(some_data)などを呼び出すことで使用するものです。それだけです!

1
Brian Armstrong