代码之家  ›  专栏  ›  技术社区  ›  josegp

RubyonRails-在Model中测试Mailer作为回调

  •  0
  • josegp  · 技术社区  · 2 年前

    我有这样的逻辑,当创建欢迎电子邮件时,我会向用户发送欢迎电子邮件。

    User.rb

    class User < ApplicationRecord
      # Callbacks
      after_create :send_registration_email
    
      private
    
      def send_registration_email
        UserConfirmationMailer.with(user: self).user_registration_email.deliver_later
      end 
    end
    

    我试着在里面测试 user_spec.rb :

    describe "#save" do
     subject { create :valid_user }
    
     context "when user is created" do
       it "receives welcome email" do
         mail = double('Mail')
         expect(UserConfirmationMailer).to receive(:user_registration_email).with(user: subject).and_return(mail)
         expect(mail).to receive(:deliver_later)
       end
     end
    end
    

    但它不起作用。我收到以下错误:

    Failure/Error: expect(UserConfirmationMailer).to receive(:user_registration_email).with(user: subject).and_return(mail)
         
           (UserConfirmationMailer (class)).user_registration_email({:user=>#<User id: 5, email: "factory10@test.io", created_at: "2023-02-18 01:09:34.878424000 +0000", ...878424000 +0000", jti: "2163d284-1349-4e48-8a2a-1b52b578921c", username: "jose_test10", icon_id: 5>})
               expected: 1 time with arguments: ({:user=>#<User id: 5, email: "factory10@test.io", created_at: "2023-02-18 01:09:34.878424000 +0000", ...878424000 +0000", jti: "2163d284-1349-4e48-8a2a-1b52b578921c", username: "jose_test10", icon_id: 5>})
               received: 0 times
    

    在回拨中测试发送电子邮件的操作时,我是否做错了什么?

    局部放电。

    我的 environment/test.rb config如下所示:

    config.action_mailer.delivery_method = :test
    config.active_job.queue_adapter = :test
    config.action_mailer.default_url_options = { :host => "http://localhost:3000" }
    

    即使我改变了 config.active_job.queue_adapter :test 下列的 this ,我得到了同样的错误。

    我尝试的另一种方法是这样的:

    expect { FactoryBot.create(:valid_user) }.to  have_enqueued_job(ActionMailer::MailDeliveryJob).with('UserConfirmationMailer', 'user_registration_email', 'deliver_now', subject)
    

    但是后来 subject 以及在中创建的用户 FactoryBot.create(:valid_user) 不同。。

    欢迎提出任何想法。非常感谢。

    0 回复  |  直到 2 年前
        1
  •  2
  •   spickermann    2 年前

    问题中的存根不起作用,因为它不会以与在实现中调用方法相同的顺序存根方法链。

    当您想要截断此方法链时

    UserConfirmationMailer.with(user: self).user_registration_email.deliver_later
    

    然后你必须先截去 with 呼叫,然后 user_registration_email 最后 deliver_later

    describe '#save' do
      subject(:user) { build(:valid_user) }
    
      let(:parameterized_mailer) { instance_double('ActionMailer::Parameterized::Mailer') }
      let(:parameterized_message) { instance_double('ActionMailer::Parameterized::MessageDelivery') }
    
      before do 
        allow(UserConfirmationMailer).to receive(:with).and_return(parameterized_mailer)
        allow(parameterized_mailer).to receive(:user_registration_email).and_return(parameterized_message)
        allow(parameterized_message).to receive(:deliver_later)
      end
    
      context 'when user is created' do
        it 'sends a welcome email' do
          user.save!
    
          expect(UserConfirmationMailer).to have_received(:with).with(user: user)
          expect(parameterized_mailer).to have_received(:user_registration_email)
          expect(parameterized_message).to have_received(:deliver_later)
        end
      end
    end
    

    注意:我不确定是否使用 instance_double 在这种情况下会起作用,因为 Parameterized 使用 method_missing 内部。虽然 实例_双 通常是首选,您可能需要使用 double 相反