Search code examples
rubyrspecrspec-railsruby-on-rails-5.2

Rspec: Failure/Error: expect(qbase).to have_received(:with_user_id).with(1)


How do I detect if the instance of CarQuery has called a method with a specific parameter? (I assume that is my issue, but please tell me if I am wrong).

Is there a better way to test this?

Error

Search#base_filters should call with_limit method on query_object when user_id is passed in
     Failure/Error: expect(qbase).to have_received(:with_user_id).with(1)

       (Double "CarQuery").with_user_id(1)
           expected: 1 time with arguments: (1)
           received: 0 times

Search Query

class Search
  def self.call(current_user, params)
    new(current_user, params).call
  end

  def initialize(current_user, params)
    @params = params
    @current_user = current_user
  end

  def call
    base_filters(CarQuery.new(@current_user)).relation
  end

  private

  def base_filters(query_object)
    query_object.with_user_id(@params[:user_id]) if @params[:user_id].present?
    query_object
  end
end

Rspec Test

RSpec.describe Search, type: :model do
  describe "#base_filters" do
    it "should call with_limit method on query_object when user_id is passed in" do

      current_user = create(:user)
      qbase =spy('CarQuery')
      expect(qbase).to have_received(:with_user_id).with(1)
      Search.call(current_user, {user_id: 1})
    end
  end
end

Solution

  • Solved with Dependency Injection

    If there is a better solution, please post it.

    Search Query

    class Search
      def self.call(current_user, params, query_object_override = nil)
        new(current_user, params, query_object_override).call
      end
    
      def initialize(current_user, params, query_object_override = nil)
        @params = params
        @current_user = current_user
        @query_object = query_object_override
      end
    
      def call
        base_filters(query_object).relation
      end
    
      private
    
      def query_object
        @query_object ||= CarQuery.new(@current_user)
      end
    
      def base_filters(query_object)
        query_object.with_user_id(@params[:user_id]) if @params[:user_id].present?
        query_object
      end
    end
    

    Rspec Test

    RSpec.describe Search, type: :model do
      describe "#base_filters" do
        it "should call with_user_id method on query_object when user_id is passed in" do
    
          current_user = create(:user)
          query_object = spy('CarQuery')
          Search.call(current_user, {user_id: 1}, query_object)
          expect(query_object).to have_received(:with_user_id )
        end
      end
    end