Skip to main content

Any Instance

rspec-mocks provides two methods, allow_any_instance_of and expect_any_instance_of, that will allow you to stub or mock any instance of a class. They are used in place of allow or expect:

allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
expect_any_instance_of(Widget).to receive(:name).and_return("Wobble")

These methods add the appropriate stub or expectation to all instances of Widget.

You can also configure the responses in the same manner.

This feature is sometimes useful when working with legacy code, though in general we discourage its use for a number of reasons:

  • The rspec-mocks API is designed for individual object instances, but this feature operates on entire classes of objects. As a result there are some semantically confusing edge cases. For example, in expect_any_instance_of(Widget).to receive(:name).twice it isn't clear whether a specific instance is expected to receive name twice, or if two receives total are expected. (It's the former.)
  • Using this feature is often a design smell. It may be that your test is trying to do too much or that the object under test is too complex.
  • It is the most complicated feature of rspec-mocks, and has historically received the most bug reports. (None of the core team actively use it, which doesn't help.)

Use allow_any_instance_of to stub a method

Given a file named "example_spec.rb" with:

RSpec.describe "allow_any_instance_of" do
it "returns the specified value on any instance of the class" do
allow_any_instance_of(Object).to receive(:foo).and_return(:return_value)

o = Object.new
expect(o.foo).to eq(:return_value)
end
end

When I run rspec example_spec.rb

Then the examples should all pass.

Use allow_any_instance_of to stub multiple methods

Given a file named "example_spec.rb" with:

RSpec.describe "allow_any_instance_of" do
context "with receive_messages" do
it "stubs multiple methods" do
allow_any_instance_of(Object).to receive_messages(:foo => 'foo', :bar => 'bar')

o = Object.new
expect(o.foo).to eq('foo')
expect(o.bar).to eq('bar')
end
end
end

When I run rspec example_spec.rb

Then the examples should all pass.

Stubbing any instance of a class with specific arguments

Given a file named "example_spec.rb" with:

RSpec.describe "allow_any_instance_of" do
context "with arguments" do
it "returns the stubbed value when arguments match" do
allow_any_instance_of(Object).to receive(:foo).with(:param_one, :param_two).and_return(:result_one)
allow_any_instance_of(Object).to receive(:foo).with(:param_three, :param_four).and_return(:result_two)

o = Object.new
expect(o.foo(:param_one, :param_two)).to eq(:result_one)
expect(o.foo(:param_three, :param_four)).to eq(:result_two)
end
end
end

When I run rspec example_spec.rb

Then the examples should all pass.

Block implementation is passed the receiver as first arg

Given a file named "example_spec.rb" with:

RSpec.describe "allow_any_instance_of" do
it 'yields the receiver to the block implementation' do
allow_any_instance_of(String).to receive(:slice) do |instance, start, length|
instance[start, length]
end

expect('string'.slice(2, 3)).to eq('rin')
end
end

When I run rspec example_spec.rb

Then the examples should all pass.

Use expect_any_instance_of to set a message expectation on any instance

Given a file named "example_spec.rb" with:

RSpec.describe "expect_any_instance_of" do
before do
expect_any_instance_of(Object).to receive(:foo)
end

it "passes when an instance receives the message" do
Object.new.foo
end

it "fails when no instance receives the message" do
Object.new.to_s
end
end

When I run rspec example_spec.rb

Then it should fail with the following output:

| 2 examples, 1 failure | | Exactly one instance should have received the following message(s) but didn't: foo |

Specify different return values for multiple calls in combination with allow_any_instance_of

Using the multiple calls feature with allow_any_instance_of results in the behaviour where multiple calls are configured on every instance. Therefore, each individual instance will return the configured return values in the order specified, and then begin to repeat the last value.

Given a file named "multiple_calls_spec_with_allow_any_instance_of.rb" with:

class SomeClass
end

RSpec.describe "When the method is called multiple times on different instances with allow_any_instance_of" do
it "demonstrates the mocked behavior on each instance individually" do
allow_any_instance_of(SomeClass).to receive(:foo).and_return(1, 2, 3)

first = SomeClass.new
second = SomeClass.new
third = SomeClass.new

expect(first.foo).to eq(1)
expect(second.foo).to eq(1)

expect(first.foo).to eq(2)
expect(second.foo).to eq(2)

expect(first.foo).to eq(3)
expect(first.foo).to eq(3) # repeats last value from here
expect(second.foo).to eq(3)
expect(second.foo).to eq(3) # repeats last value from here

expect(third.foo).to eq(1)
expect(third.foo).to eq(2)
expect(third.foo).to eq(3)
expect(third.foo).to eq(3) # repeats last value from here
end
end

When I run rspec multiple_calls_spec_with_allow_any_instance_of.rb

Then the examples should all pass.