如何从 ActionMailer::Base.deliveries 中获取值

3

我正在为我的应用程序创建测试。

当创建一个询价请求时,我会向用户发送确认电子邮件。我还会向校对人员发送一封电子邮件进行通知。

我仍在学习Ruby,我相信有更好的方法来编写以下代码:

def email_exists?(email_address)
    ActionMailer::Base.deliveries.each do |m|
        if m[:to].to_s == email_address
            return true
        end
    end
end

def email_with_subject_exists?(email_address, email_subject)
    ActionMailer::Base.deliveries.each do |m|
        if m[:to].to_s == email_address && m[:subject].to_s == email_subject
            return true
        else
            return false
        end
    end
end

我发现如果我不包含“return false”,那么邮件的整个内容都会被输出。如有改进此代码的帮助将不胜感激。

以下是ActionMailer :: Base.deliveries的内容:

[#<Mail::Message:70094817191440, Multipart: true, Headers: <Date: Thu, 01 Sep 2016 15:50:35 +0700>, <From: from@example.com>, <To: peterjohnson1@example.com>, <Message-ID: <57c7ebdb1b5f4_2ab93fc03545e1f850559@Mitchell-Goulds-MacBook-Air.local.mail>>, <Subject: Welcome to the ProvenWord team!>, <Mime-Version: 1.0>, <Content-Type: multipart/alternative; boundary="--==_mimepart_57c7ebdb16e49_2ab93fc03545e1f85046d"; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>, #<Mail::Message:70094829223120, Multipart: true, Headers: <Date: Thu, 01 Sep 2016 15:50:35 +0700>, <From: from@example.com>, <To: peterjohnson2@example.com>, <Message-ID: <57c7ebdb23188_2ab93fc03545e1f850725@Mitchell-Goulds-MacBook-Air.local.mail>>, <Subject: Welcome to the ProvenWord team!>, <Mime-Version: 1.0>, <Content-Type: multipart/alternative; boundary="--==_mimepart_57c7ebdb229aa_2ab93fc03545e1f8506be"; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>, #<Mail::Message:70094772574660, Multipart: true, Headers: <Date: Thu, 01 Sep 2016 15:50:35 +0700>, <From: from@example.com>, <To: peterjohnson3@example.com>, <Message-ID: <57c7ebdb28936_2ab93fc03545e1f850960@Mitchell-Goulds-MacBook-Air.local.mail>>, <Subject: Welcome to the ProvenWord team!>, <Mime-Version: 1.0>, <Content-Type: multipart/alternative; boundary="--==_mimepart_57c7ebdb27bf6_2ab93fc03545e1f850835"; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>, #<Mail::Message:70094829778220, Multipart: true, Headers: <Date: Thu, 01 Sep 2016 15:50:35 +0700>, <From: from@example.com>, <To: peterjohnson4@example.com>, <Message-ID: <57c7ebdb2c982_2ab93fc03545e1f85116b@Mitchell-Goulds-MacBook-Air.local.mail>>, <Subject: Welcome to the ProvenWord team!>, <Mime-Version: 1.0>, <Content-Type: multipart/alternative; boundary="--==_mimepart_57c7ebdb2c064_2ab93fc03545e1f85104b"; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>, #<Mail::Message:70094829991680, Multipart: true, Headers: <Date: Thu, 01 Sep 2016 15:50:35 +0700>, <From: from@example.com>, <To: peterjohnson5@example.com>, <Message-ID: <57c7ebdb30c2b_2ab93fc03545e1f85135c@Mitchell-Goulds-MacBook-Air.local.mail>>, <Subject: Welcome to the ProvenWord team!>, <Mime-Version: 1.0>, <Content-Type: multipart/alternative; boundary="--==_mimepart_57c7ebdb30465_2ab93fc03545e1f85123c"; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>, #<Mail::Message:70094777280260, Multipart: true, Headers: <Date: Thu, 01 Sep 2016 15:50:35 +0700>, <From: from@example.com>, <To: johnpeters@example.com>, <Message-ID: <57c7ebdbb8421_2ab93fc03545e1f8515e5@Mitchell-Goulds-MacBook-Air.local.mail>>, <Subject: Your ProvenWord quotation request has been delivered>, <Mime-Version: 1.0>, <Content-Type: multipart/alternative; boundary="--==_mimepart_57c7ebdbb76fa_2ab93fc03545e1f8514ee"; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>]

你在这里使用 #each 的方式是错误的。如果你只想要查找电子邮件,使用 #filter/#find。#each 将返回枚举。例如:[1,2].each { |i| i == 1 } 返回 [1,2],所以你的函数正在返回 ActionMailer::Base.deliveries。你的 #each 正在执行工作但没有做/返回任何东西。 - Peter R
ActionMailer::Base.deliveries.select {|m| m[:to].to_s == QuotationRequest.last.client.email } 仍然返回 ActionMailer::Base.deliveries 的内容。 - chell
它们是否都匹配电子邮件地址?#select返回所有true [1,2].select {|i| i>0 } 返回 [1,2]。#find返回第一个true [1,2].find {|i| i>0 } 返回 1 - Peter R
2个回答

5
我通常会这样做(使用RSpec):
it "sends correct email" do
  UserMailer.welcome_email(user).deliver
  ActionMailer::Base.deliveries.last.tap do |mail|
    expect(mail.from).to eq(["myapp@awesome.com"])
    expect(mail.subject).to eq("Welcome #{user.name}")
  end
end

编辑:

有几种方法可以实现。我个人喜欢将发送内容和消息包含的逻辑分开处理。

控制器(最好)/模型(可能)操作如下:

def something
  Mailer.a(item).deliver
  Mailer.b(item).deliver
end

测试正确的电子邮件是否发送:

it "sends correct number of emails" do
  expect do
    ## Trigger your stuff here (#something above)
  end.to change{ ActionMailer::Base.deliveries.size }.by(2)
end

编辑2: ^^这^^实际上并不会测试发送的正确的两个电子邮件。为此,您可以执行类似于ActionMailer :: Base.deliveries.map { |e | e [: subject]}. Sort == [“asubject”,“bsubject”] .sort 的操作,但是当您更改主题时,这将是脆弱的。由您决定要在此处执行/测试什么。(还要查看assert Mailer.recieves(:a).with(obj) (我忘记了确切的语法,而且我不知道您正在使用哪个测试框架,但它们都有类似的东西。)

测试电子邮件内容是否正确

it "Mailer#a has correct email content" do
  Mailer.a(user).deliver
  ActionMailer::Base.deliveries.last.tap do |mail|
    expect(mail.from).to eq(["myapp@awesome.com"])
    expect(mail.subject).to eq("Welcome #{user.name}")
  end
end
## repeat for Mailer#b

在我的应用程序中,我想测试在创建新的报价请求后是否发送了正确的电子邮件。由于发送的邮件很多,因此对于这些测试,我不能使用last。我必须使用特定的电子邮件地址进行实际搜索。您有使用filter/find执行此操作的示例吗? - chell
我同意检查主题会非常脆弱。我将更改为检查是否存在引用请求的链接,因为必须存在该链接。我喜欢您将测试分成a和b两个部分的方式。在我的发送报价请求表单的功能测试中,我想测试提交表单后是否发送了正确的电子邮件。我也会测试邮件程序。我使用Rspec。谢谢Peter抽出时间来帮助我。还有很多要学习的东西。 - chell
puts ActionMailer::Base.deliveries.select {|m| m.to.include?(email_address)} 返回 ActionMailer::Base 邮件对象。有什么想法? - chell

3

在Peter R.的帮助下,我找到了以下解决方案:

class EmailHelper

        #checks if the email exists in ActionMailer::Base to see if it was sent and to the correct email address
        def email_exists?(email_address)
            ActionMailer::Base.deliveries.select {|m| m.to.include?(email_address)}
        end

        def email_with_subject_exists?(email_address, email_subject)
            ActionMailer::Base.deliveries.select {|m| (m.to.include?(email_address) && m.subject.include?(email_subject))}
        end

    end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接