问题
I am trying to test sending an email with Sidekiq and I am having an error which means it doesn't enqueue since my test shows it didn't change from 0 to 1 in size. Could it be I am missing something out or how can I fix this?
Error
expected `Array#size` to have changed by 1, but was changed by 0
0) Sending Mail sends email to sidekiq
Failure/Error:
expect do
OrderPointsMailer.paid_order_email(customer_detail.id).deliver_later
end.to change(Sidekiq::Worker.jobs, :size).by(1)
expected `Array#size` to have changed by 1, but was changed by 0
# ./spec/requests/order_points_mailer_spec.rb:9:in `block (2 levels) in <top (required)>'
1 example, 1 failure, 0 passed
binding.pry
This shows Sidekiq::Worker.jobs
is empty array
and it is understandable why it failed but I do not know how I could fix this.
[1] pry(#<RSpec::ExampleGroups::SendingMailWithSidekiq>)>Sidekiq::Worker.jobs
=> []
app/jobs/order_points_job.rb
# frozen_string_literal: true
class OrderPointsJob < ApplicationJob
def perform(customer_email)
customer_detail = CustomerDetail.find_by(email: customer_email)
return unless customer_detail
OrderPointsMailer.paid_order_email(customer_detail.id).deliver_later # This call send email to sidekiq process
end
end
RSpec
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Sending Mail with Sidekiq', type: :request do
it 'sends email to sidekiq' do
customer_detail = create(:customer_detail)
expect do
OrderPointsMailer.paid_order_email(customer_detail.id).deliver_later
end.to change(Sidekiq::Worker.jobs, :size).by(1)
end
end
rails_helper.rb
require 'sidekiq/testing'
Sidekiq::Testing.fake!
回答1:
You probably should use the method count
instead of size
:
.to change(Sidekiq::Worker.jobs.reload, :count).by(1)
Take a look at the size
implementation:
From: /home/toptal/.rvm/gems/ruby-2.5.5/gems/activerecord-6.0.0/lib/active_record/relation.rb @ line 260:
Owner: ActiveRecord::Relation
Visibility: public
Number of lines: 3
def size
loaded? ? @records.length : count(:all)
end
Also take a look on the matcher implementation (https://github.com/rspec/rspec-expectations/blob/master/lib/rspec/matchers/built_in/change.rb#L82:L85)
I'm guessing that the receiver (Sidekiq::Worker.jobs
in your case) will be evaluated once, and then the size
would be called twice on the same objects collection, without reloading.
One other approach you could take would be
.to change { Sidekiq::Worker.jobs.reload.size }.by(1)
But this would be a bit wasteful in case you have more records in the DB, because each time the AR objects will need to be created (and they're not used)
来源:https://stackoverflow.com/questions/59059988/sending-an-email-with-sidekiq-rspec-test-failed-because-array-is-empty-and-could