Ruby on Rails Minitest 在一个测试中进行多个模拟

问题描述 投票:0回答:1

我正在使用 Minitest 和 Ruby on Rails 编写单元测试。

有时我需要同时模拟多个事物。

例如,在测试向用户触发通知的操作时,我可能想一次性模拟两个外部服务器(例如:

SmsClient
EmailClient
)。

我可以这样做:

test 'my test case' do
  SmsClient.stub :send, nil do
    EmailClient.stub :send, nil do
      get my_controller_url
    end
  end
end

这可行,但是我现在需要在同一个调用中再模拟一个类。

我担心这些

stub
调用的嵌套会失控。

问题:有没有办法可以在不使用嵌套的情况下在这些服务上设置模拟?

注意:这些示例只是假设。

ruby-on-rails ruby unit-testing minitest
1个回答
0
投票

我不知道是否有任何 Minitest 帮助程序可以简化此操作,但这里有一些可以减少嵌套的核心 Ruby 代码。

stubs = [
  proc { |block| SmsClient.stub(:send, nil, &block) },
  proc { |block| EmailClient.stub(:send, nil, &block) },
]

tests = proc do
  # ...
end

stubs.reduce(:<<).call(tests)
# results in
# (stubs[0] << stubs[1]).call(tests)
#
# aka
# stubs[0].call(stubs[1].call(tests))
#
# aka
# SmsClient.stub(:send, nil) do
#   EmailClient.stub(:send, nil) do
#     # ...
#   end
# end

请注意,您可以通过将

:<<
更改为
:>>
来反转嵌套。


您可以在某处定义一个助手来简化此操作:

def stub_all(*stubs, &test_block)
  stubs = stubs.map do |subject, method, return_value|
    proc { |block| subject.stub(method, return_value, &block) }
  end

  stubs.reduce(:<<).call(test_block)
end
stub_all(
  [SmsClient,   :send, nil],
  [EmailClient, :send, nil],
) do
  # ...
end
© www.soinside.com 2019 - 2024. All rights reserved.