ActionMailer不在测试环境中发送确认电子邮件 - Rails 4

时间:2016-06-10 16:39:31

标签: ruby-on-rails-4 rspec devise capybara

我正在使用Rails(4.2.6),Ruby(2.2.4),Devise(4.1.1),Capybara(2.7.1),Capybara-email(2.5.0),Email_spec(2.1.0) ,Rspec(3.4.0)和Postgres(0.18.4)

我将应用程序从Rails 4.1.15升级到4.2.6之后,几个认证&注册测试失败。在升级之前,所有测试都正确通过。代码在开发环境中按预期工作(例如,确认电子邮件在Rails服务器终端中发送和查看)。未送达电子邮件的问题仅发生在测试环境中。

这是失败的rspec ./spec/features/users/authentification_spec.rb:56:

#Sign up User

    visit "/"
    click_link "Sign up"

    find(:css, "#user_email").set("tester9@example.com")
    find(:css, "#user_password").set("password900")
    find(:css, "#user_password_confirmation").set("password900")

    expect {
            click_button "Sign up"      
        }.to change{ ActionMailer::Base.deliveries.size}.by(1)

当用户完成表单并单击“注册”按钮时,页面将重定向到“关于”页面,并且正如预期的那样,将显示以下Flash消息:“已向您的电子邮件发送带有确认链接的消息地址。请点击链接激活您的帐户。“
使用save_and_open_page,我确认了上述行为。但是,规范失败并出现以下错误:

Failure/Error:
   expect {
           click_button "Sign up"  
       }.to change{ ActionMailer::Base.deliveries.size}.by(1)

   expected result to have changed by 1, but was changed by 0
 # ./spec/features/users/authentification_spec.rb:56:in `block (2 levels) in <top (required)>'

错误表明ActionMailer :: Base.deliveries数组中没有消息对象。 Pry的结果证实ActionMailer :: Base.deliveries数组确实是空的:

[1] pry(main)> mail = ActionMailer::Base.deliveries
=> []

以下是运行规范时的测试日志:

Started POST "/users" for 127.0.0.1 at 2016-06-09 16:16:25 -0700
Processing by RegistrationsController#create as HTML
  Parameters: {"utf8"=>"✓", "user"=>{"email"=>"tester9@example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
  [1m[35m (0.8ms)[0m  SAVEPOINT active_record_1
  [1m[36mUser Exists (3.3ms)[0m  [1mSELECT  1 AS one FROM "users" WHERE "users"."email" = 'tester9@example.com' LIMIT 1[0m
  [1m[35mUser Exists (1.9ms)[0m  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('tester9@example.com') LIMIT 1
  [1m[36mSQL (2.1ms)[0m  [1mINSERT INTO "users" ("email", "encrypted_password", "signup_as", "created_at", "updated_at", "confirmation_token",     "confirmation_sent_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"[0m  [["email", "tester9@example.com"], ["encrypted_password", "$2a    $04$Vruf8j0A.DdOZLPe0qjVp.4PxzdR7sCdLF4FfyAr4dQSxcQAjpAwy"], ["created_at", "2016-06-09 23:16:25.095386"], ["updated_at", "2016-06-09 23:16:25.095386"],     ["confirmation_token", "EmY8JyaVAxAfiq7oQ98z"], ["confirmation_sent_at", "2016-06-09 23:16:25.097581"]]
  [1m[35m (0.4ms)[0m  RELEASE SAVEPOINT active_record_1
Redirected to http://www.example.com/about
Completed 302 Found in 113ms (ActiveRecord: 9.6ms)

日志表示已发送确认电子邮件,但deliveryies数组为空。为什么会这样?由于某种原因,记录是否未在测试数据库中提交或持久存在?我已阅读有关未送达邮件的相关帖子,但尚未找到解决我问题的方法。

test.rb中的相关代码:

  # Tell Action Mailer not to deliver emails to the real world.
  # The :test delivery method accumulates sent emails in the
  # ActionMailer::Base.deliveries array.  

  config.action_mailer.delivery_method = :test
  config.action_mailer.perform_deliveries = true

来自rails_helper.rb的相关内容:

require 'rspec/rails'
require 'devise'
require 'capybara/rails'
require 'database_cleaner'
require 'capybara/poltergeist'
require 'capybara/email/rspec'
require 'email_spec'

  # Includes Devise test helpers (e.g., lets you use Devise's "sign_in" method in tests)

  config.include Devise::TestHelpers, :type => :controller 
  config.include Warden::Test::Helpers

devise.rb的相关注释掉的代码:

  # Configure the class responsible to send e-mails.
   #config.mailer = 'Devise::Mailer'

邮件投递在开发过程中按预期工作生产。测试环境出了什么问题?我该如何解决?谢谢!

2 个答案:

答案 0 :(得分:4)

查看设计 - https://github.com/plataformatec/devise/blob/4-1-stable/lib/devise/models/confirmable.rb#L48 - 它在after_commit回调中发送确认电子邮件 - 如果您在启用事务测试的情况下运行,则永远不会调用after_commit回调(因为数据库事务已回滚且从未提交)所以电子邮件永远不会发送。禁用该测试的基于事务的测试,它可能会起作用。

答案 1 :(得分:1)

只是将Tom Walpole和上面提到的代码之间的讨论总结为可能不会查看评论的浏览器的顶级答案,他们的解决方案(假设您使用DatabaseCleaner)是进行以下修改:

<强> rails_helper.rb

# lots of boilerplate and
# other things at the top of this file, but you'll
# eventually see....

RSpec.configure do |config|

  # ... other config stuff ...

  # sometime after this key line, you want to add:
  config.before(:each, truncation: true) do
    DatabaseCleaner.strategy = :truncation
  end

  # ... other config stuff ...

end

对于此处有问题的测试,您希望将其修改为如下所示(请注意在以“it”开头的行中添加“truncation:true”)

<强> something_spec.rb

# ... other stuff ...
describe "some function" do
  it "performs a function correctly", truncation: true do
    # your test
    # goes here
  end
end