Moving to 3.9 - the demise of allow_any_instance_of

20 views
Skip to first unread message

Jack Royal-Gordon

unread,
Sep 25, 2020, 11:31:41 AM9/25/20
to rs...@googlegroups.com
I’ve just upgraded from Rspec 2.99 to 3.9, and have discovered that “allow_any_instance_of” is no longer supported. I’m not sure how best to go about replacing it, as it is in use in most of my tests. I have a User class, and most tests involve a user. Behind the scenes, many of the user methods call the Stripe API to adjust subscriptions, view and preview invoices, etc. Currently, I’ve got the following in “spec_helper.rb”:

  config.before(:each) do
    allow_any_instance_of(User).to receive(:send_to_stripe).and_return(true)
  end

In most cases the calls to the Stripe API go through that method (I used instance stubs as necessary in tests that use other facets of the Stripe API). I understand that the preferred approach is to stub an instance rather than a whole class. But to do this, everywhere I create a user I would have to add “allow(xxx).to receive(:send_to_stripe).and_return(true). Most (if not all) of my users are created with calls to FactoryBot.In the interest of DRYing my tests, is there a way I can leverage that to set a stub on the instance being created by FactoryBot?

Jon Rowe

unread,
Sep 25, 2020, 12:28:12 PM9/25/20
to rs...@googlegroups.com
Hello!

We consider `allow_any_instance_of(…)` a feature for working with legacy code and not to be the first choice, but it’s currently still supported, you can find the documentation here:


To replace it we recommend you be specific about your instances.

e.g for your example:

```
config.before(:each) do
  allow(User).to receive(:find) do
    user = instance_double(User)
    allow(user).to receive(:send_to_stripe).and_return(true)
    user
  end
end
```

But really, I wouldn’t do that at all, because why does every test need this? I’d more likely recommend stubbing the right call at the right time, with the right calls. Otherwise my code could call send_to_stripe at any point and my tests would never notice...

Jack Royal-Gordon

unread,
Sep 25, 2020, 3:43:24 PM9/25/20
to rs...@googlegroups.com
Hi Jon,

I get what you’re saying, and I agree in general, but this case is a little different. Every account that gets activated gets sent to Stripe, so unless I’m testing the activation process itself, the account will get sent to Stripe. And as the account is built out to facilitate whatever test we are running, #send_to_stripe can be sent more than once. In fact, it’s designed to be able to be called more often than strictly necessary without a bad outcome. So I’m not worried about extra calls, but I need to stop any calls from actually proceeding into the routine and calling the Stripe API.

I am looking into alternatives to using allow_any_instance_of, but then I have to put my tests in the  middle of where the user gets instantiated (for example, when a web request comes in it does a #find_by(auth_token: xxx), which means in every controller test for a logged in user I will have to stub that call so that I can return an object that I have access to.

In an unrelated question, I’ve been using Webrat for matchers like has_selector?, but when I moved to Rspec 3.99, it stopped recognizing Webrat matchers. Is there a require and/or include that must be added to get access to those? I looked at the webrat docs, and what they recommended (e.g. require “webrat-rails”) does not work. I saw one StackOverflow answer that indicated that we should use Capybara for this. Is that the case?

--
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 view this discussion on the web visit https://groups.google.com/d/msgid/rspec/dejalu-217-5242bc7e-977b-41a6-b172-a7e4525c8701%40jonrowe.co.uk.

Jon Rowe

unread,
Sep 26, 2020, 4:06:56 AM9/26/20
to rs...@googlegroups.com
You’ve superbly illustrated why we consider the feature to be useful for legacy code, sometimes systems are built in a way that makes it hard to get access to individual instances. You don’t have to replace the allow_any_instance_of calls, they work fine in 3.x and will be supported in one way or another in 4.x I would concentrate on your other upgrade issues first!

It’s been a long time since I’ve used webrat, but I vaguely remember the issue you’re seeing, I think you need to include the matchers directly into your tests, e.g. add `include Webrat::Matchers` where appropriate, I’m not sure why that changed.

Hope that helps!
Reply all
Reply to author
Forward
0 new messages