Rspec can't stub where or find_by_, only find

7.6k views Asked by At

I'm going to share several pairs of run code and test code. Basically, the test code is only working when I use a find on the object class, but the problem is find is the one method I DON'T want to use because I'm not looking for the primary key!

Approach 1: stubbing :where with Plan.all so that first can be called on it

#run code
@current_plan = Plan.where(stripe_subscription_id: event.data.object.lines.data.first.id).first

#test code
@plan = Plan.new #so this is the first Plan that I'd like to find
Plan.stub(:where).and_return(Plan.all)

#result of @current_plan (expecting @plan)
=> nil

Approach 2: chain stubbing :where and :first

#run code
@current_plan = Plan.where(stripe_subscription_id: event.data.object.lines.data.first.id).first

#test code
@plan = Plan.new #so this is the first Plan that I'd like to find
Plan.stub_chain(:where, :first).and_return(@plan)

#result of @current_plan (expecting @plan)
=> nil

Approach 3: stubbing custom :find_by

#run code
@current_plan = Plan.find_by_stripe_subscription_id(event.data.object.lines.data.first.id)

#test code
@plan = Plan.new
Plan.stub(:find_by_stripe_subscription_id).and_return(@plan)

#result of @current_plan (expecting @plan)
=> nil

Approach 4: stubbing :find WORKS! But I can't find by primary key... so I ideally need approach 3 to work...

#run code
@current_plan = Plan.find(2) #for giggles, to make sure the stub is ignoring the 2 argument

#test code
@plan = Plan.new
Plan.stub(:find).and_return(@plan)

#result of @current_plan (expecting @plan)
=> @plan

I guess another answer would be how can I creatively use :find with arguments, even though I understand this isn't best practice...

2

There are 2 answers

0
james On BEST ANSWER

Ok I have a temporary solution, which is just to use select. I.e.,

#run code
@current_plan = Plan.select { |p| p.stripe_subscription_id == event.data.object.lines.data.first.id }.first

#test code
@plan = Plan.new
Plan.stub_chain(:select, :first).and_return(@plan)

#result of @current_plan (expecting @plan)
=> @plan

Still though... if others have thoughts please chime in... I'm now a little academically curious as to why the where or where, first stubs aren't working.

The find_by_stripe_subscription_id, I've done some more testing, and even the expectations of methods fail on custom find_by methods so of course a stub won't work. BUT, see zetetic's answer below, and maybe it's just me the gods hate...

1
zetetic On

You can stub those methods. All these tests pass:

require 'rails_helper'

RSpec.describe Foo, type: :model do
  let(:foo) { double(name: "foo") }

  it "works with find" do
    expect(Foo).to receive(:find).and_return(foo)
    expect(Foo.find(1)).to eq foo
   end

  it "works with find_by" do
    expect(Foo).to receive(:find_by_name).and_return(foo)
    expect(Foo.find_by_name("foo")).to eq foo
  end

  it "works with where" do
    expect(Foo).to receive(:where).and_return([ foo ])
    expect(Foo.where(name: "foo")).to eq [foo]
  end
end