在 Rails 方法中测试延迟作业邮件程序

Test delayed job mailers in Rails method

我有一个 rails 方法允许用户提交评论并向交易对手发送一封使用延迟作业的电子邮件。

def update_review
  @review.add_review_content(review_params)
  ReviewMailer.delay.review_posted(@review.product_owner, params[:id])
end

我正在尝试为此添加一个 rspec 测试,以检查邮件是否正确发送以及发送给谁。延迟的工作 运行 在 test 上创建后立即完成,因为我希望其他工作像更新产品所有者总体评级的工作立即完成。

所以电子邮件确实被触发了,但我如何为它添加测试?

编辑:添加当前测试

我目前的测试是:

describe 'PUT #update the review' do

  let(:attr) do
    { rating: 3.0, raw_review: 'Some example review here' }
   end

   before(:each) do
     @review = FactoryBot.create :review
     put :update, id: @review.id, review: attr
   end

   it 'creates a job' do
     ActiveJob::Base.queue_adapter = :test
     expect {
       AdminMailer.review_posted(@coach, @review.id).deliver_later
     }.to have_enqueued_job
   end 

   it { should respond_with 200 }

end

这确实测试了邮件程序是否正常工作,但我想测试它是否也在方法流程中被正确触发。

听起来您想要的是确保 update_review 方法将作业排入队列以将正确的电子邮件发送给正确的收件人。这是实现此目的的更简单方法:

describe 'PUT #update the review' do
  let(:params) { { rating: rating, raw_review: raw_review } }
  let(:rating) { 3.0 }
  let(:raw_review) { 'Some example review here' }
  let(:review) { FactoryBot.create(:review) }
  let(:delayed_review_mailer) { instance_double(ReviewMailer) } 

  before do
    # assuming this is how the controller finds the review...
    allow(Review).to receive(:find).and_return(review)

    # mock the method chain that enqueues the job to send the email
    allow(ReviewMailer).to receive(:delay).and_return(delayed_review_mailer)
    allow(delayed_review_mailer).to receive(:review_posted)

    put :update, id: review.id review: params
  end

  it 'adds the review content to the review' do
    review.reload
    expect(review.rating).to eq(rating) 
    expect(review.raw_review).to eq(raw_review)
  end

  it 'sends a delayed email' do
    expect(ReviewMailer).to have_received(:delay)
  end

  it 'sends a review posted email to the product owner' do
    expect(delayed_review_mailer)
      .to have_received(:review_posted)
      .with(review.product_owner, review.id)
  end
end

我更喜欢这种方法的原因是 a) 它可以在根本不接触数据库的情况下完成(通过将工厂换成双实例),并且 b) 它不会尝试测试 Rails 已经由构建 Rails 的人员测试过,例如 ActiveJob 和 ActionMailer。您可以信任 Rails 对那些 类.

自己的单元测试