0

我有一个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作业的方法中是硬编码的。所以我不能伪造它并将其作为依赖项传递。有没有办法可以在 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 堆栈无法做到这一点,我愿意使用外部库。

4

3 回答 3

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 实例。该模拟进一步验证调用被调用。

于 2016-01-28T20:03:42.617 回答
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
于 2017-08-17T23:59:21.737 回答
0

不确定如何在 Minitest 中编写此代码,但您可以使用模拟(此处为 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'ed ,否则此测试将失败。

免责声明:这可能不是 100% 的功能,但这应该是正确的想法,假设我已经正确阅读了 OP 的 Q。

于 2016-01-26T21:14:50.897 回答