I have a PlantTree
job that calls a PlantTree
service object. I would like to test the job to ascertain that it instantiates the PlantTree
service with a tree
argument and calls the call
method.
I'm not interested in what the service does or the result. It has its own tests, and I don't want to repeat those tests for the job.
# app/jobs/plant_tree_job.rb
class PlantTreeJob < ActiveJob::Base
def perform(tree)
PlantTree.new(tree).call
end
end
# app/services/plant_tree.rb
class PlantTree
def initialize(tree)
@tree = tree
end
def call
# Do stuff that plants the tree
end
end
As you can see, the PlantTree
class is hard coded in the perform
method of the job. So I can't fake it and pass it in as a dependency. Is there a way I can fake it for the life time of the perform method? Something like...
class PlantTreeJobTest < ActiveJob::TestCase
setup do
@tree = create(:tree)
end
test "instantiates PlantTree service with `@tree` and calls `call`" do
# Expectation 1: PlantTree will receive `new` with `@tree`
# Expectation 2: PlatTree will receive `call`
PlantTreeJob.perform_now(@tree)
# Verify that expections 1 and 2 happened.
end
end
I'm using Rails' default stack, which uses MiniTest. I know this can be done with Rspec, but I'm only interested in MiniTest. If it's not possible to do this with MiniTest only, or the default Rails stack, I'm open to using an external library.
You should be able to do something like
mock= MiniTest::Mock.new
mock.expect(:call, some_return_value)
PlantTree.stub(:new, -> (t) { assert_equal(tree,t); mock) do
PlantTreeJob.perform_now(@tree)
end
mock.verify
This stubs the new method on PlantTree, checks the argument to tree and then returns a mock instead of a PlantTree instance. That mock further verifies that call was called.