I have a Rails model
which is deactivated
by default. A Sidekiq job is activating
it after success. All my specs are failing after implementing this job. How can I "stub" / "fake" that database change to get my specs falling without changing all of them to Model.unscoped
Maybe somehow a helper_function could be called to mock that job function.
class Model
attribute :active # false by default in Database
default_scope { where(:active => true) }
after_create :run_job, if: -> { saved_change_to_something? }
def run_job
MyJob.perform_async(id)
end
def mark_visible!
update_column(:active, true)
end
def stuff_to_do_in_job
update_column(:active, false)
# do long term stuff
end
end
class MyJob
include Sidekiq::Job
def perform(id)
model = Model.find(id)
if stuff_to_do_in_job
model.mark_visible!
end
end
RSpec.describe Model, type: :model do
it "is active after saved"
model = Model.new(model_attributes)
model.save
# --> • <--- somehow mock here a running job, setting model to true
expect(model.active).to be_truthy
end
Of course I can change all functions where any Model.find
is needed to set to Model.unscoped.find
but that looks awkward
Do I have a test modelling issue?
CodePudding user response:
I don't think you would want to mock the job after each Model
creation. Just create the Model
with active: true
in your specs that do not test that specific behaviour.
Then you can create one spec to make sure that the job is being scheduled i.e.:
expect{ model.save }.to have_enqueued_job(MyJob)
And finally create a new file for the specs of MyJob
, where you assert that it is doing what it should do when executed.
CodePudding user response:
I got it!!! Thank you for all your suggestions.
It was a design problem:
What I did was to deactivate the Model in the model itself, and after that fired a job, where within this job it was activated again.
The way I am doing it now, is deactivating it within the Model.
There are two ways:
- Deactivate it within the Job and at the end activating it again or
- Deactivating it right before calling the Job and activating it at the end of the job.
class Model
attribute :active # false by default in Database
default_scope { where(:active => true) }
after_create :run_job, if: -> { saved_change_to_something? }
def run_job
# or deactivate it here
mark_invisible!
MyJob.perform_async(id)
end
def mark_visible!
update_column(:active, true)
end
def mark_invisible!
update_column(:active, false)
end
def stuff_to_do_in_job
# don't do it here mark_invisible!
# do long term stuff
end
end
class MyJob
include Sidekiq::Job
def perform(id)
model = Model.find(id)
model.mark_invisible! # either here
if stuff_to_do_in_job
model.mark_visible!
end
end