Object.any_instance should_receive vs expect() to receive
Asked Answered
D

2

81

The following piece of code works as expected:

Object.any_instance.should_receive(:subscribe)

But when using the new rspec expectation it does not work:

expect(Object.any_instance).to receive(:subscribe)

The error is:

expected: 1 time with any arguments
received: 0 times with any arguments

How can I make this work with expect() to receive?

Dietary answered 10/7, 2013 at 9:11 Comment(0)
P
166

There's now a not very well documented method called expect_any_instance_of that handles the any_instance special case. You should use:

expect_any_instance_of(Object).to receive(:subscribe)

Google expect_any_instance_of for more info.

Phonic answered 10/7, 2013 at 18:14 Comment(8)
+1 for "not very well documented". Still the case. rubydoc.info/gems/rspec-mocks/RSpec/Mocks/…Balanced
I have been using allow_any_instance_of. Is it an alias of this method?Slippery
@Slippery They're different, with the allow methods stubbing behaviour and expect methods testing for behaviour. For example, allow(my_obj).to receive(:method_name).and_return(true) stubs my_obj.method_name() so if it's called in the test it simply returns true. expect(my_obj).to receive(:method_name).and_return(true) doesn't change any behaviour, but sets up a test expectation to fail if my_obj.method_name() isn't called later in the test or doesn't return true.Johansen
Thanks @Saigo. Makes sense now.Slippery
This syntax is deprecated. Is there any hints on how to do this in today's syntax?Endanger
It is deprecated because it is not clear what you mean by expect_any_instance_of (especially if you have to test several interactions on the same object VS different object), however I still find this very convenient. (source: some thread in the RSpec forums)Mcghee
For the syntax deprecation, see @Arreth's answerDepose
Syntax works fine without deprecation warnings for meEnrika
I
9

Just a heads up, expect_any_instance_of is now considered deprecated behaviour according to Jon Rowe (key rspec contributor). The suggested alternative is to use the instance_double method to create a mock instance of your class and expect calls to that instance double, as described in that link.

Jon's method is preferred (since it can be used as a generalized test helper method). However if you find that confusing, hopefully this implementation for your example case can help make sense of the intended method:

mock_object = instance_double(Object) # create mock instance
allow(MyModule::MyClass).to receive(:new).and_return(mock_object) # always return this mock instance when constructor is invoked

expect(mock_object).to receive(:subscribe)

Good luck! 🙏🏽

Impaction answered 16/9, 2019 at 17:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.