Setting constraints on a mock while mutating object for constraint in test definition

71 views
Skip to first unread message

Sean Monroe

unread,
May 11, 2016, 9:20:29 PM5/11/16
to rspec
I'm not sure how to write a subject for this, so sorry if it's confusing. It's best to just show an example. I'm having the following problem with RSpec 3.4.0 and Ruby 1.9.3.

Given this RSpec config:


 
RSpec.configure do |config|
    config
.mock_with :rspec
    config
.run_all_when_everything_filtered = true
    config
.filter_run :focus
 
end


And these tests:

      it 'test1' do
        test_obj
= double
        test_hash
= { a: 3 }
        expect
(test_obj).to receive(:get).with(a_hash_including(test_hash)).and_return(5)


        test_hash
[:a] = 4
        expect
(test_obj).to receive(:get).with(a_hash_including(test_hash)).and_return(6)


        expect
(test_obj.get({ a: 3 })).to eq(5)
        expect
(test_obj.get({ a: 4 })).to eq(6)
     
end


      it
'test2' do
        test_obj
= double
        test_hash
= { a: 3 }
        expect
(test_obj).to receive(:get).with(a_hash_including(test_hash)).and_return(5)


        test_hash_dup
= test_hash.dup
        test_hash_dup
[:a] = 4
        expect
(test_obj).to receive(:get).with(a_hash_including(test_hash_dup)).and_return(6)


        expect
(test_obj.get({ a: 3 })).to eq(5)
        expect
(test_obj.get({ a: 4 })).to eq(6)
     
end

test1 fails with:


   
Failure/Error: expect(test_obj.get({ a: 3 })).to eq(5)

       
#<Double (anonymous)> received :get with unexpected arguments
         expected
: (a hash including {:a => 4})
              got
: ({:a=>3})
       
Diff:
       
@@ -1,2 +1,2 @@
       
-["a hash including {:a => 4}"]
       
+[{:a=>3}]

test2 succeeds.

test2 is almost identical to test1, with the only difference being that I make a copy of the hash I'm setting a constraint with before mutating it and passing it to the matcher and constraint.

This was very unintuitive to me, and took a while to figure out (I got lucky honestly). 

Is this a bug? If not, is there a part of the documentation that explains this?

Thanks!

Jon Rowe

unread,
May 11, 2016, 9:29:40 PM5/11/16
to rs...@googlegroups.com
Hi Sean

This isn’t a bug in RSpec, it’s a “feature” of how Ruby works, the first example fails because the hash is the same when it’s checked by the expectation, you’re mutating the hash before it's checked and the same reference is used in both expectations. 

Whilst this may be unintuitive to you it’s not something we can handle, this is the same behaviour as you’d find elsewhere in your code, for example in rails, if you pass a params hash into another object, mutate it outside that object, the value inside that object will also change.

Cheers
Jon

Jon Rowe
---------------------------

--
You received this message because you are subscribed to the Google Groups "rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+un...@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/8f87469c-d1ea-4735-9146-d4b1bd8a02f2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sean Monroe

unread,
May 11, 2016, 11:29:07 PM5/11/16
to rspec
Ah, I didn't even think that RSpec would be reusing the original object when it checked the expectation. That makes sense though, thanks for the quick response!!
Reply all
Reply to author
Forward
0 new messages