ruby-on-rails 使用Rspec和factory_bot测试邮件服务器

1qczuiv0  于 2023-05-19  发布在  Ruby
关注(0)|答案(1)|浏览(121)
  • 嘿,伙计们,我需要帮助,我是新的测试和测试我的邮件,但我不明白你得到这个错误,当我运行我的测试。
  • '预期ActionMailer::Base.deliveries.size已更改% 1,但已更改% 2'
  • 电子邮件由after_create钩子触发
  • 我的代码按预期工作,但测试失败。任何有帮助的人都很感激。
    验证邮件.rb
# frozen_string_literal: true

class VerifyMailer < ApplicationMailer
  def verification_email(user)
    @user = user
    mail(to: user.email, subject: 'verification code')
  end
end

verify_mailer_spec.rb

# frozen_string_literal: true

require 'rails_helper'
# include ActiveJob::TestHelper

RSpec.describe VerifyMailer, type: :mailer do
  let(:user) { create(:user) }
  let(:mail) { VerifyMailer.verification_email(user).deliver_now }

  it 'renders the receiver email' do
    expect(mail.to).to eq([user.email])
  end
  it 'renders the subject' do
    expect(mail.subject).to eq('verification code')
  end
  it 'renders the sender email' do
    expect(mail.from).to eq(['mutebigod10@gmail.com'])
  end
end

user.rb

# frozen_string_literal: true

class User < ApplicationRecord
  after_create :send_user_otp
  attr_writer :login

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable ,

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, authentication_keys: [:username]
  has_many :payments
  validates :email, :username, presence: true, uniqueness: true
  validates :username, format: { with: /\A[a-zA-Z0-9_.]*\z/,
                                 message: ' only allow letter, number, underscore and punctuation marks' }

  # Loggin with user_name
  def login
    @login || username
  end

  def send_user_otp
    unverify!
    otp = generate_codes
    update_column(:otp_code, otp)
    VerifyMailer.verification_email(self).deliver_now
    touch(:otp_sent_at)
  end

  def unverify!
    update_column(:verified, false)
  end

  def generate_codes
    loop do
      code = rand(0o00000..999_999).to_s
      break code unless code.length != 6
    end
  end
end
  • 我已经将config.action_mailer.delivery_method =:test添加到environment/test.rb
  • 我还使用factory_bot_rails创建用户
FactoryBot.define do
  factory :user do
    sequence(:email) { |n| "person#{n}@example.com" }
    sequence(:username) { |n| "user#{n}" }
    password { '!Mutebi2' }
    password_confirmation { '!Mutebi2' }
  end
end
to94eoyn

to94eoyn1#

在大多数情况下,计算机完全按照您的要求执行操作:

let(:user) { create(:user) }
  let(:mail) { VerifyMailer.verification_email(user).deliver_now }

使用FactoryBot创建user会触发任何/所有回调:

class User < ApplicationRecord
  after_create :send_user_otp

所以create(:user)在创建后调用:send_user_otp
然后您发送另一封电子邮件VerifyMailer.verification_email(user).deliver_now
因此,ActionMailer::Base.deliveries.size的变化为2。
VerifyMailer测试中,您正在测试电子邮件的属性,因此您不需要实际保存用户或实际发送电子邮件。
如果您需要电子邮件的示例,只需删除deliver_now即可。您可以使用build代替create,使用user

RSpec.describe VerifyMailer, type: :mailer do
  let(:user) { build(:user) }
  let(:mail) { VerifyMailer.verification_email(user) }

  it 'renders the receiver email' do
    expect(mail.to).to eq([user.email])
  end
  it 'renders the subject' do
    expect(mail.subject).to eq('verification code')
  end
  it 'renders the sender email' do
    expect(mail.from).to eq(['mutebigod10@gmail.com'])
  end
end

User测试中,您可以验证创建用户也会创建电子邮件:

RSpec.describe User, type: :model do
  let(:user) { build(:user) }

  describe "after create" do
    it "calls #send_user_otp" do
      expect(user).to receive(:send_user_otp)
    end
  end

  describe "#send_user_otp" do
    it "calls VerifyMailer.verification_email" do
      expect(VerifyMailer).to receive(:verification_email).with(user)

      user.send(:send_user_otp)
    end
  end
end

请注意,我实际上根本没有测试ActionMailer::Base.deliveries.size。这是一个服务或请求测试,应该基于完整的实现,例如:
填写本表时:

  • 创建用户记录
  • 一封电子邮件被发送<=这里是您测试电子邮件队列收到一封电子邮件的地方

您的User模型不负责VerifyMailerApplicationMailer和任何其他处理delver_now的代码,它只负责调用VerifyMailer并将user示例传递给它。
VerifyMailer不负责处理邮件的发送,它创建邮件并将其传递给ActionMailer
让你的测试集中在你的代码的责任上,这将使它们不那么脆弱。
如果您在ActionMailer设置中进行了更改,您不希望User测试开始失败。

相关问题