如何测试一个方法在对象中的其他方法之后被调用?

How to test a method is invoked after other in an object?

我有以下 class:

class Foo
  def initialize(foobar:)
    @foobar = foobar
  end

  def call
    return if foobar.blank?
    do_something_here
  end
end

正在模型的 after_commit 回调中调用:

included { after_commit :invoke_method_in_poro, on: %I[create update] }

private

def invoke_method_in_poro
  Foo.new(foobar: to_json).call
end

现在,当我尝试测试 call 是否被调用时,我需要首先存根新方法,因为我收到此错误:

NameError: undefined method `call' for class `Foo'
Did you mean?  caller

使用此代码:

foo = Foo
new_mock = Minitest::Mock.new
new_mock.expect :call, nil
foo.stub(:call, new_mock) do
  create(:model)
end
mock.verify

我的问题是,我最终如何测试 call 是否被调用?

你 运行 进入了 Minitest 的一个特性:当 call 定义在一个方法上时,似乎 minitest 堆栈中的某些东西试图在定义一个对象时调用它。

鉴于此测试设置:

require 'minitest/autorun'

class Foo
  def call
  end
end

class Bar
  def test
    Foo.new.call
  end
end

describe "Bar" do
  it "invokes foo.call" do
    mock = Minitest::Mock.new(Foo)
    mock.expect(:call, nil)

    Foo.stub :new, mock do |args|
      Bar.new.test
      mock.verify
    end
  end
end

它按照描述失败了。但是如果你把call重命名为my_call,它就通过了:

require 'minitest/autorun'

class Foo
  def my_call
  end
end

class Bar
  def test
    Foo.new.my_call
  end
end

describe "Bar" do
  it "invokes foo.my_call" do
    mock = Minitest::Mock.new(Foo)
    mock.expect(:my_call, nil)

    Foo.stub :new, mock do |args|
      Bar.new.test
      mock.verify
    end
  end
end

相同的测试在 RSpec 下通过:

class Foo
  def call
  end
end

class Bar
  def test
    Foo.new.call
  end
end

describe "Bar" do
  it "invokes foo.call" do
    mock = double
    expect(mock).to receive(:call)
    expect(Foo).to receive(:new).and_return(mock)
    Bar.new.test
  end
end