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

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

如何检测 CarQuery 实例是否调用了具有特定参数的方法? (我认为这是我的问题,但如果我错了请告诉我)。

有没有更好的方法来测试这个?

错误

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

搜索查询

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 测试

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

必须在 spy 上调用方法才能工作

如果你使用的是间谍,那么你需要调用它上面的方法,然后测试是否接收到该方法。请参阅有关间谍 here 的 rspec 文档。或者,您也可以使用 double。他们都很相似,但你不能指望替身能像间谍一样工作。

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')
      qbase.with_user_id(1) # <-------- you need to add this line here first
      ## but does qbase even have a method called 'with_user_id'? if not,
      ## it will still fail
      expect(qbase).to have_received(:with_user_id).with(1) 
      # If you don't add the line above, of course it will fail, 
      ## you haven't sent qbase any messages! It won't work otherwise.
      ## I'm not sure what the line below is doing in relation to your tests?
      Search.call(current_user, {user_id: 1})
    end
  end
end

通过依赖注入解决

如果有更好的解决办法,请post吧。

搜索查询

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 测试

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