首页 > 解决方案 > 在 RSpec 匹配器中,如何使在模型回调中创建的实例可用

问题描述

我尝试测试一个模型。创建被测模型后,它会从另一个模型创建一个对象,并根据另一个对象的 ID 发送一封电子邮件。

# model under test

class AccountabilityBuddy < ApplicationRecord
  after_save_commit :send_consent_inquiry

  def send_consent_inquiry
    consent_tracker = BuddyConsent.create!(accountability_buddy_id: self.id)
    BuddyMailer.with(buddy: self, consent_link: consent_tracker.id).buddy_request.deliver_later
  end
...

这是我迄今为止尝试过的:

# the model test

RSpec.describe AccountabilityBuddy, type: :model do
  subject(:buddy) { build(:accountability_buddy) }
  
    describe 'after_save callback' do
      let(:saving) do
        buddy.save!
        buddy.reload
      end

      it 'sends an email to the buddy' do
        # how that works: https://stackoverflow.com/questions/22988968/testing-after-commit-with-rspec-and-mocking/30901628#comment43748375_22989816
        expect { saving }
          .to have_enqueued_job(ActionMailer::MailDeliveryJob)
                .with('BuddyMailer', 'buddy_request', 'deliver_now', params: {buddy: buddy, consent_link: BuddyConsent.last.id }, args: [])
        # Test fails, BuddyConsent.last.id is nil
      end

      it 'creates a new BuddyConsent' do
        expect { saving }.to(change { BuddyConsent.all.count }.from(0).to(1))
        # Test passes
      end
    end
...

第一个测试失败,因为 BuddyConsent.last.id 为 nil。我知道这BuddyConsent是正确生成的,因为 ID 在let块内可用:

      let(:saving) do
        buddy.save!
        buddy.reload
        BuddyConsent.last.id # => "8be42055-112c-4ba6-bd1b-61b73946fb6e"
      end

我如何使它在匹配器中可用,为什么它脱离上下文?

标签: ruby-on-railsrubytestingrspecrspec-rails

解决方案


推荐阅读