Reputation: 571
I have a Sidekiq job that looks something like this:
class Arbitrary::MarkSold < ApplicationJob
def perform(item_id)
return if Rails.env.test?
item = Item.find_by(item_id)
item.sold = true
item.save
end
end
And a corresponding RSpec test that looks like this:
Rspec.describe Arbitrary::MarkSold, type: :job do
describe 'perform' do
it 'runs' do
expect(Arbitrary::Marksold).to receive(:perform).and_return(nil)
MarkSold.new.perform(34)
end
end
end
When I try to run this test, I get a failure with this error:
Arbitrary::MarkSold does not implement: perform`.
However, I can clearly see that Arbitrary::MarkSold
has a perform
method.
I've read Method Stubs but couldn't make heads or tails out of it, or figure out how to apply it to this situation.
I'd greatly appreciate any pointers or links to documentation other than the one I've linked. As a beginner I find that the rspec docs aren't very beginner-friendly. Thank you in advance!
Ruby version: 2.4.9 Rails version: 5.1.7 RSpec version: 3.7
Upvotes: 1
Views: 6759
Reputation: 63
For the next users stumbling upon this page from Google (like me)...
If you are looking to test your Sidekiq job, consider that maybe what you are trying to test is the content of perform
and if so you can test it directly like any other ruby object.
source: https://github.com/sidekiq/sidekiq/wiki/Testing#testing-workers-directly
Upvotes: 1
Reputation: 741
There are some issues in what you are doing:
expect(Arbitrary::Marksold).to receive(:perform).and_return(nil)
In the snippet above, you are expecting that the class Arbitrary::Marksold
to receive perform
, but you are not expecting that an instance should receive perform
. That's why you are getting the does not implement: perform
error.
You could (I did not test it, so you may have to adjust one or another thing):
marksold_spy = instance_spy(Arbitrary::Marksold)
allow(Arbitrary::Marksold).to(receive(:new).and_return(marksold_spy))
expect(marksold_spy).to(receive(:perform).and_return(nil))
But the above isn't the way how I'd do it. The way I'd do it:
class Arbitrary::MarkSold
include Sidekiq::Worker
def perform(item_id)
item = Item.update(item_id, sold: true)
end
end
And my test:
Rspec.describe Arbitrary::MarkSold, type: :job do
describe 'perform' do
it 'runs' do
item = create(:item, sold: false)
Sidekiq::Testing.inline! do
described_class.perform_async(item.id)
end
expect(item.reload.sold).to be_truthy
end
end
end
To read a little bit more about Sidekiq::Testing
, you can go through this link
Upvotes: 0
Reputation: 214
I use have_enqueued_job
to test if the job gets enqueued assuming that is what you are trying to test. It seems like it.
https://relishapp.com/rspec/rspec-rails/docs/matchers/have-enqueued-job-matcher
Upvotes: 1