8

我写了一个 RSpec 集成测试。根据 test.log,我可以看到它已经发送了一封电子邮件,但是当我尝试使用 ActionMailer::Base.deliveries 访问该电子邮件时,它总是显示它是空的。

我已经阅读了其他类似的问题并尝试了一切。我难住了。

这是使用 Capybara/RSpec 的代码:

it "should notify owner" do

  puts "Delivery method: #{ActionMailer::Base.delivery_method.inspect}"
  # This returns: ":test", which is correct

  # Get other guests to do the review
  @review = Review.last
  share_link = "http://#{@account.subdomain}.cozimo.local:#{Capybara.server_port}/review/#{@review.slug}"

  visit(share_link)

  fill_in "email", :with => @user1.email
  fill_in "password", :with => "foobar"

  click_button "Start Review"

  # Add a comment
  click_on "ice-global-note-button"
  find(:css, "#ice-global-note-panel > textarea.ui-corner-all").set "Foo"
  click_on "ice-global-note-submit-button"

  # Test is failing here. WTF? The array should not be empty
  ActionMailer::Base.deliveries.empty?.should be_false

  # Check that a notification email was sent to the owner
  open_email(@owner.email)
  current_email.should have_content "Hi #{@owner.first_name}"

end

如上所示, config.action_mailer.delivery_method = :test

在 test.log 中,显示邮件真的发送了!

Sent mail to somebody1@example.com (62ms)
Date: Tue, 29 Jan 2013 13:53:48 -0500
From: Review Studio <support@cozimo.com>
To: somebody1@example.com
Message-ID: <51081abcd9fbf_5bd23fef87b264a08066@Leonards-MacBook-Pro.local.mail>
Subject: Notes added for Test
Mime-Version: 1.0
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: 7bit

Hi Bruce,

Just letting you know that you have new notes added to the review:

  Project: Test
  Description: Test description
  URL: http://ballistiq.cozimo.local:3000/review/625682740

Thanks,

Review Studio
Completed 200 OK in 170ms (Views: 0.2ms | ActiveRecord: 4.3ms)
4

6 回答 6

8

这是使用 Capybara 和 Selenium 进行的集成测试。因此,您必须等待应用程序实际发送邮件,然后再检查它是否已发送。

注意 - 这解决了问题,但通常是不好的做法

添加一个sleep 1告诉 rspec 在触发发送邮件事件后等待。然后通过检查 ActionMailer::Base.deliveries 数组并通过它来恢复。

如前所述,这通常是不好的做法,因为它会减慢测试速度。

更好的方法

集成测试根本不应该测试邮件是否发送。测试应该被划分为被测试类的明确职责。因此,我们会以不同的方式构建测试,以便我们只测试在另一个类中发送的邮件(控制器或资源测试)。我们还可以使用期望值来检查对 mail 方法的调用是否确实进行了,尽管我们仍然可能会遇到时间问题。

于 2013-01-29T19:37:53.120 回答
5

您永远不应该在规格上使用睡眠或那些耗时的方法,我只会减慢您的规格!

尝试在您的邮件中使用期望,在测试开始时添加类似

mail = mock(mail)
mail.should_receive(:deliver)
YourMailer.should_receive(:your_method).once.and_return(mail)

这样你就不必等待,你实际上是在测试你必须测试的东西(代码创建和传递邮件)而不是邮件程序代码(你只在邮件对象上调用传递,实际传递是一项工作的 ActionMailer 测试,你在你的应用程序上与它无关,你应该相信调用这些方法是有效的)

于 2013-01-30T00:55:22.053 回答
1

在我的情况下config.action_mailer.perform_deliveriesfalse用于测试环境。

于 2020-04-02T12:42:12.643 回答
0

您也可以使用此 wait_for_ajax 帮助程序而不是 sleep 用于您的 javascript POST。它会让 Capybara 等待 ajax 完成。

module WaitForAjax
  def wait_for_ajax
   Timeout.timeout(Capybara.default_wait_time) do
    loop until finished_all_ajax_requests?
   end
  end

  def finished_all_ajax_requests?
   page.evaluate_script('jQuery.active').zero?
  end
end

RSpec.configure do |config|
  config.include WaitForAjax, type: :feature
end

来源: https ://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara

于 2015-03-18T22:38:23.573 回答
0

我认为一般来说你想sleep()在你的测试中避免。如果您正在使用 Capybara 进行集成测试,您只需要使用等待的方法。

例如,此测试间歇性失败(valid_step_7发送电子邮件):

it "should get past step 7 and send an email" do
  valid_step_5_no_children
  valid_step_7

  expect(ActionMailer::Base.deliveries.count).to eq(1)
  expect(page).to have_content "I AM JOHN DOE"
end

这是因为它正在完成最后一步 (valid_step_7) 并立即检查 'ActionMailer::Base.deliveries.count' 以查看它是否等于 1,但它不一定没有时间填充交付数组(来自反正我的调试)。

自从我翻转测试以首先检查下一页上的内容,给ActionMailer::Base.deliveries填充时间并执行检查以来,我没有出现随机失败:

it "should get past step 7 and send an email" do
  valid_step_5_no_children
  valid_step_7

  expect(page).to have_content "I AM JOHN DOE"
  expect(ActionMailer::Base.deliveries.count).to eq(1)
end

我怀疑sleep(1)会起作用,但我认为你在不需要时强迫睡眠。

于 2016-06-22T04:23:22.993 回答
0

我遇到了同样的问题,最后我找到了一个简单的解决方案,不确定是否是最好的 wat:欢迎所有赞赏或更正。

首先在 environtments/test.rb 中添加这一行, config.active_job.queue_adapter = :inline即使我们输入了代码,这也会执行“deliver_now”deliver_later

在测试中添加对电子邮件的期望(我总是显示一条消息,告诉您已发送电子邮件......),例如:

expect(page).to have_content("We have sent a confirmation e-mail")
expect(ActionMailer::Base.deliveries.count).to eq(1)

第一个期望将等到 2 秒(这是默认超时,尽管可以通过 配置Capybara.default_wait_time = 2s)。

所以,在我的例子中,把这个期望和添加这个配置行config/environments/test.rb就足以正确通过测试

于 2017-10-30T21:25:47.640 回答