RSpec:匹配receive_message_chain的参数

dor*_*emi 6 rspec ruby-on-rails

我试图存根:

Thing.where(uuid: options['uuid']).first
Run Code Online (Sandbox Code Playgroud)

通过:

allow(Thing).to receive_message_chain(:where, :first)
  .with(uuid: thing_double.uuid)
  .and_return(nil)
Run Code Online (Sandbox Code Playgroud)

但这是回归:

 #<Double (anonymous)> received :first with unexpected arguments
         expected: ({:uuid=>123})
              got: (no args)
Run Code Online (Sandbox Code Playgroud)

我应该以不同的方式验证消息链的参数吗?

Nat*_*use 9

以下是我们解决类似情况的方法:

expect(Theme).to receive(:scoped).and_return(double('scope').tap do |scope| 
  expect(scope).to receive(:includes).with(:categories).and_return scope
  expect(scope).to receive(:where).with(categories: { parent_id: '1'}).and_return scope
  expect(scope).to receive(:order).with('themes.updated_at DESC').and_return scope
  expect(scope).to receive(:offset).with(10).and_return scope
  expect(scope).to receive(:limit).with(10000)
end)
Run Code Online (Sandbox Code Playgroud)

最近几个月,纯粹是偶然,我发现您实际上可以按照消息链的顺序链接“with”调用。因此,前面的例子就变成了这样:

expect(Theme).to receive_message_chain(:scoped, :includes, :where, :order, :offset, :limit).with(no_args).with(:categories).with(categories: { parent_id: '1'}).with('themes.updated_at DESC').with(10).with(10000)
Run Code Online (Sandbox Code Playgroud)


zet*_*tic 7

当参数与最终方法以外的任何内容相关时,您似乎无法with结合使用receive_message_chain.因此消息:

#<Double (anonymous)> received :first with unexpected arguments
Run Code Online (Sandbox Code Playgroud)

这是有道理的 - RSpec如何知道链中的哪个方法应该接收参数?

要验证参数期望,请不要对链进行存根,只需存根 where

allow(Thing).to receive(:where).with(uuid: 1).and_return([])
expect(Thing.where(uuid: 1).first).to eq nil
Run Code Online (Sandbox Code Playgroud)

或者省略参数:

 allow(Thing).to receive_message_chain(:where, :first).and_return(nil)
 expect(Thing.where(uuid: 1).first).to eq nil
Run Code Online (Sandbox Code Playgroud)

receive_message_chain不推荐IMO.来自文档:

你应该考虑使用receive_message_chain代码气味