メッセージチェーン
特定の状況で、receive
の代わりにreceive_message_chain
を使用して、メッセージのチェーンをスタブ化することができます。
allow(double).to receive_message_chain("foo.bar") { :baz }
allow(double).to receive_message_chain(:foo, :bar => :baz)
allow(double).to receive_message_chain(:foo, :bar) { :baz }
上記の3つの形式のいずれかが与えられた場合:
double.foo.bar # => :baz
Rails/ActiveRecordでの一般的な使用例:
allow(Article).to receive_message_chain("recent.published") { [Article.new] }
receive_message_chain
は、and_return
、and_yield
などの応答の評価と一緒に使用するように設計されています。レガシーの理由から、stub_chain
との互換性もサポートされていますが、その使用は良い慣行とは見なされていません。将来のバージョンでは、stub_chain
の互換性のサポートが削除される可能性があります。
exactly
(つまり、exactly(2).times
)のようなカスタマイズはサポートされていません。
警告:
チェーンは任意の長さにすることができ、これによりデメテルの法則を破ることが非常に簡単になります。そのため、receive_message_chain
の使用はコードの臭いと見なすべきです。すべてのコードの臭いが実際の問題を示すわけではありませんが(フルエントインターフェースを考えてみてください)、receive_message_chain
は依然として壊れやすい例を生み出します。たとえば、スペックでallow(foo).to receive_message_chain(:bar, :baz => 37)
と書いて、実装がfoo.baz.bar
を呼び出す場合、スタブは機能しません。
receive_message_chain
を使用したチェーンは、チェーンの適用方法について曖昧さを生み出し、実装コードの複雑な相互作用に設計上の圧力をかけます。そのため、receive_message_chain
はreceive
の完璧な代替ではありません(詳細な説明については、Issue 921を参照してください)。double
やinstance_double
などの他のモッキングメソッドは、これらの相互作用を持つコードをテストするためのより良い方法を提供します。
ダブルにreceive_message_chain
を使用する
以下の内容で「receive_message_chain_spec.rb」という名前のファイルがあるとします:
RSpec.describe "Using receive_message_chain on a double" do
let(:dbl) { double }
example "using a string and a block" do
allow(dbl).to receive_message_chain("foo.bar") { :baz }
expect(dbl.foo.bar).to eq(:baz)
end
example "using symbols and a hash" do
allow(dbl).to receive_message_chain(:foo, :bar => :baz)
expect(dbl.foo.bar).to eq(:baz)
end
example "using symbols and a block" do
allow(dbl).to receive_message_chain(:foo, :bar) { :baz }
expect(dbl.foo.bar).to eq(:baz)
end
end
When I run rspec receive_message_chain_spec.rb
Then the examples should all pass.