我正在使用 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
调用的嵌套会失控。
问题:有没有办法可以在不使用嵌套的情况下在这些服务上设置模拟?
注意:这些示例只是假设。
我不知道是否有任何 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