我有一个调用PlantTree
服务对象的PlantTree
作业。我想测试这项工作,以确定它使用PlantTree
参数实例化tree
服务并调用call
方法。
我对服务的作用或结果不感兴趣。它有自己的测试,我不想重复这些测试。
# 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
如您所见,PlantTree
类在作业的perform
方法中进行了硬编码。所以我不能伪造它并将其作为依赖项传递。有没有办法可以在执行方法的生命周期内伪造它?有点像...
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
我正在使用Rails的默认堆栈,它使用MiniTest。我知道这可以用Rspec完成,但我只对MiniTest感兴趣。如果不能仅使用MiniTest或默认的Rails堆栈,我可以使用外部库。
答案 0 :(得分:1)
您应该可以执行类似
的操作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
这将在PlantTree上存根新方法,将参数检查到树,然后返回模拟而不是PlantTree实例。该模拟进一步验证调用是否被调用。
答案 1 :(得分:0)
不确定如何在Minitest中编写此内容,但您可以使用mock(此处为RSpec语法):
expect(PlantTree).to receive(:new).with(tree)
expect_any_instance_of(PlantTree).to receive(:call)
# NOTE: either of the above mocks (which are expectations)
# will fail if more than 1 instance receives the method you've mocked -
# that is, PlantTree#new and PlantTree#call
# In RSpec, you can also write this using `receive_message_chain`:
# expect(PlantTree).to receive_message_chain(:new, :call)
job = PlantTreeJob.new(@tree)
job.perform
除非PlantTree
服务对象(1)通过#new
实例化,并且(2)获得#call
',否则此测试将失败。
免责声明:这可能不是100%功能,但这应该是正确的想法,假设我已正确读取OP的Q。
答案 2 :(得分:0)
plant_tree_mock= MiniTest::Mock.new
dummy = Object.new
tree = Object.new
plant_tree_mock.expect(:call, dummy, [tree])
PlantTree.stub(:new, plant_tree_mock) do
PlantTreeJob.perform_now(tree)
end
assert plant_tree_mock.verify