Ruby 如何使用RSpec忽略您应该接收的额外消息?

Ruby 如何使用RSpec忽略您应该接收的额外消息?,ruby,rspec,sinatra,expectations,Ruby,Rspec,Sinatra,Expectations,规格: Sinatra应用程序: before do Logger.should_receive( :write ).with 'Log message 1' end it 'works' do get '/' end 由于“日志消息2”,此规范失败。如何告诉RSpec忽略任何其他消息,并且只测试预期的消息?您需要在消息预期之前存根将接收消息的方法 get '/' Logger.write( 'Log message 1' ) Logger.write( 'Log m

规格:

Sinatra应用程序:

before do
  Logger.should_receive( :write ).with 'Log message 1'    
end

it 'works' do
  get '/'
end

由于“日志消息2”,此规范失败。如何告诉RSpec忽略任何其他消息,并且只测试预期的消息?

您需要在消息预期之前存根将接收消息的方法

get '/'
  Logger.write( 'Log message 1' )
  Logger.write( 'Log message 2' )
end
方法存根是指向对象(实数或测试双精度)的指令,用于响应消息返回已知值

在这种情况下,告诉
记录器
对象在收到
写入
消息(第一次)时返回值
nil

因此,您的
before
块应该如下所示

# RSpec >= 3
allow(Logger).to receive(:write).and_return(nil)  # Most appropriate in this case
allow(Logger).to receive(:write) { nil }  # Prefer block when returning something of a dynamic nature, e.g. a calculation
allow(Logger).to receive_messages(write: nil)  # Prefer hash when stubbing multiple methods at once, e.g. receive_messages(info: nil, debug: nil)

这个问题有点老了,但是在这里找到了我的方法,我想我会回答它,假设rspecmockv3

如果您关心对象是否接收到某条消息,而不是它是否只接收到该消息,那么预先存根对象,然后用
have_received
断言该消息效果很好

receive(:…)
have\u receive(:…)

从最初的问题继续,假设它在rspec mocks v3中重写,我的解决方案是:

before do
  Logger.stub(write: nil)
  Logger.should_receive(:write).with('Log message 1')
end

注意,将断言放在末尾很重要,因为它在调用时检查存根状态,而不是按照惯例在完成时检查存根状态。

Logger.stub(:write)
worked。为什么需要这样做?
stub
允许实例在不实际执行方法调用的情况下接收消息
should_receive
设置一个期望值,这意味着如果消息未按预期接收,则规范应失败,包括参数匹配。在这种情况下,您希望预期特定调用并允许常规调用,从而调用这两个方法。实际上,
stub
调用表示“如果
Logger
也使用其他参数调用
write
,那么也没关系”。
Logger.应该接收(:write)。至少(:一次)
。或者您需要断言确切的消息吗?我想知道如何使用
have_received
…或者如果有特殊原因,
received
have_received
的工作方式不同,我认为
expect(Logger)(记录器)。to receive(:write)。使用('Log message 1')
断言记录器只接收到那条消息(或您可以添加的任何其他内容)。这是一个微妙且没有很好记录的区别。我将设法抽出时间向rspec Mock提交PR,以更新其自述文件/文档。是的,这似乎是当前的行为。可能只有
方法可以明确说明这一点,并且可以与
接收
已接收
预期(记录器)一起使用.接收(:写入)。带有('Log message 1')。仅限
before do
  Logger.stub(write: nil)
  Logger.should_receive(:write).with('Log message 1')
end
allow(Logger).to receive(:write)
get '/'
expect(Logger).to have_received(:write).with('Log message 1')