如何在 Minitest 中模拟一系列方法

How to mock a chain of methods in Minitest

看起来正确地存根方法链的唯一信息来源是 10 多年前:

https://www.viget.com/articles/stubbing-method-chains-with-mocha/

RoR: Chained Stub using Mocha

找不到有关如何正确执行此操作的信息,我感到非常沮丧。我想基本上模拟 Rails.logger.error.

更新:我基本上想做一些像

一样简单的事情
def my_action
  Rails.logger.error "My Error"
  render json: { success: true }
end

并想编写这样的测试:

it 'should call Rails.logger.error' do
  post my_action_url
  ???
end

我认为您可能误解了术语 chain of methods 在这种情况下,它们表示 ActiveRecord::Relation 链,这些链可以附加另一个。在你的情况下 Rails.loggerActiveSupport::Logger 就是这样。您可以像这样模拟记录器并测试您的案例:

mock = Minitest::Mock.new
mock.expect :error, nil, ["My Error"] # expect method error be called
Rails.stub :logger, mock do
 post my_action_url
end
mock.verify

除此之外,我个人不喜欢他们通过存根进行测试的方式chain of method,它太详细了,例如:我有一个查询前十名用户的测试用例,我为链写了一个存根User.where().order()... 等方法一开始没问题,然后假设我需要重构查询或创建数据库视图顶级用户以优化性能,如您所见,我需要再次存根方法链。为什么我们只是将测试用例视为黑盒,在我的例子中,测试用例不应该知道(也不关心)我如何实现查询,它只检查结果是否应该是前十名用户。

更新

因为每个请求 Rails 内部调用 Logger.info 那么如果你想忽略它,你可以 stub 该函数:

def mock.info; end

如果你想测试被调用方法的数量或验证错误消息,你可以使用 spy(我想你已经知道那些单元测试概念)

mock = Minitest::Mock.new
def mock.info; end
spy = Hash.new { |hash, key| hash[key] = [] }
mock.expect(:error, nil) do |error|
 spy[:error] << error
end

Rails.stub :logger, mock do
 post my_action_url
end

assert spy[:error].size == 1 # call time
assert spy[:error] == ["My Error"] # error messages

最好创建一个 test helper 方法来重用上面的代码。如果需要,您可以改进辅助方法的行为,使其类似于 Jest 中的 mockImplementation