无法在receive_message_chain rspec中使用非stubbed方法

时间:2017-12-04 04:26:12

标签: ruby-on-rails rspec

我对receive_message_chain rspec 3.6有一个奇怪的问题

 allow_any_instance_of(Order).to receive_message_chain('line_items.find') 
{LineItem.first}

当我执行order.line_items而不是返回一个集合时,它返回一个<Double (anonymous)>对象,这不是我想要的。

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

当您告诉RSpec在特定对象上设置receive_message_chain('line_items.find')时,它需要设置正确的存根以使链工作。

首先,RSpec在对象上存根方法line_items。接下来它需要存根方法find,但是这个方法需要在方法line_items的返回值上存根。由于我们使用了该方法,因此RSpec需要提供一些返回值,这可以是存根的目标。

因此,RSpec将方法line_items的返回值设置为具有方法find存根的匿名双精度。因此,一旦您将receive_message_chain设置为'line_items.find',则在调用line_items时,对象将始终返回匿名双精度。由于您使用allow_any_instance_of,这意味着方法line_items现在存在于Order的所有实例上。

如果可能的话,我建议考虑尝试从您的规范中删除allow_any_instance_ofreceive_message_chain的用法,因为如果您真的无法更改设计,它们实际上是在规范中使用的快捷方式你的代码https://relishapp.com/rspec/rspec-mocks/docs/working-with-legacy-code/message-chains

但是,如果无法做到这一点,您可以删除receive_message_chain并自行设置链。

line_items_stub = double 
# or line_items_stub = Order.new.line_items
# or line_items_stub = [LineItem.new, LineItem.new]
# or line_items_stub = the object that you want

allow_any_instance_of(Order).
  to receive(:line_items).
  and_return(line_items_stub)
allow(line_items_stub).to receive(:find)

如果您能够删除allow_any_instance_of,则可以使用and_call_original在该具体实例上调用line_items的实际实现,即可将message_chain存在。