How to test with Rspec if an email is delivered

☆樱花仙子☆ 提交于 2019-12-02 18:50:24

Assuming your test environment is set up in the usual fashion (that is, you have config.action_mailer.delivery_method = :test), then delivered emails are inserted into the global array ActionMailer::Base.deliveries as Mail::Message instances. You can read that from your test case and ensure the email is as expected. See here.

Configure your test environment to accumulate sent mails in ActionMailer::Base.deliveries.

# config/environments/test.rb
config.action_mailer.delivery_method = :test

Then something like this should allow you to test that the mail was sent.

# Sample parameters you would expect for POST #create.
def reservation_params
  { "reservation" => "Drinks for two at 8pm" }
end

describe MyController do
  describe "#create" do
    context "when a reservation is saved" do
      it "sends a confirmation email" do
        expect { post :create, reservation_params }.to change { ActionMailer::Base.deliveries.count }.by(1)
      end
    end
  end
end

Note that my example uses RSpec 3 syntax.

Jules Copeland

I know I'm late to the party with this one, but for future Googlers...

I think a better solution to this problem is answered here

The previously accepted answer is testing the Mailer itself (inside the controller spec). All you should be testing for here is that the Mailer gets told to deliver something with the right parameters.

You can then test the Mailer elsewhere to make sure it responds to those parameters correctly.

ReservationMailer.should_receive(:confirm_email).with(an_instance_of(Reservation))

For the record, to anyone using rspec 3.4 and ActiveJob to send async emails, you could check this with:

expect {
  post :create, params
}.to have_enqueued_job.on_queue('mailers')

This is way how to test that Mailer is called with right arguments. You can use this code in feature, controller or mailer spec:

delivery = double
expect(delivery).to receive(:deliver_now).with(no_args)

expect(ReservationMailer).to receive(:confirm_email)
  .with('reservation')
  .and_return(delivery)

To add a little more, make sure if you're going to stub out a call using should_receive that you have an integration test elsewhere testing that you're actually calling the method correctly.

I've been bit a few times by changing a method that was tested elsewhere with should_receive and having tests still pass when the method call was broken.

If you prefer to test the outcome rather than using should_receive, shoulda has a nice matcher that works like the following:

it { should have_sent_email.with_subject(/is spam$/) }

Shoulda documentation

More information on using Shoulda Matchers with rSpec

GuilPejon

If you're using Capybara with Capybara Email and you sent an email to test@example.com, you can also use this method:

email = open_email('test@example.com')

And then you can test it like this:

expect(email.subject).to eq('SUBJECT')
expect(email.to).to eq(['test@example.com'])

Try email-spec

describe "POST /signup (#signup)" do
  it "should deliver the signup email" do
    # expect
    expect(UserMailer).to(receive(:deliver_signup).with("email@example.com", "Jimmy Bean"))
    # when
    post :signup, "Email" => "email@example.com", "Name" => "Jimmy Bean"
  end
end

more examples here: https://github.com/email-spec/email-spec#testing-in-isolation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!