rspec-mocks
rspec-mocks copied to clipboard
Expect to have_received(method).with({}) fails when method modifies the Hash
What Ruby, Rails and RSpec versions are you using?
Ruby version: ruby 2.3.7p456 (2018-03-28 revision 63024) [x86_64-darwin17] Rails version: Rails 5.2.1 Rspec version: RSpec 3.8
Observed behaviour
I am using Rspec to test the presence of a method call with the correct parameters.
I invoke the method call
with
my_callable.call({})
and I test the call using
expect(my_callable).to have_received(:call).with({})
When call
modifies the provided hash argument, like context[:value] = true
, this test fails, when it should succeed. This produces the output:
#<MyCallable:0x00007f9505aa5518> received :call with unexpected arguments
expected: ({})
got: ({:value=>true})
Diff:
@@ -1,2 +1,2 @@
-[{}]
+[{:value=>true}]
It appears that the expect
call is referencing the hash modified in memory, rather than a saved copy of the hash when the call was actually made.
Expected behaviour
I expect this test to pass.
Because the call to the method call
was made with an empty hash {}
, the expect statement
expect(my_callable).to have_received(:call).with({})
is correct.
Can you provide an example app?
Link to repo: https://github.com/bvrooman/Rspec-Issue-2044
I found that this contrived code can reproduce the issue:
Inside any _spec
file:
class MyCallable
def call(context)
context[:value] = true
end
end
let(:my_callable) { MyCallable.new }
describe 'MyCallable #call' do
it 'is called with the right arguments' do
allow(my_callable).to receive(:call).and_call_original
my_callable.call({})
expect(my_callable).to have_received(:call).with({})
end
end
This results in the following failure:
#<MyCallable:0x00007f9505aa5518> received :call with unexpected arguments
expected: ({})
got: ({:value=>true})
Diff:
@@ -1,2 +1,2 @@
-[{}]
+[{:value=>true}]