Stub ActiveRecord ::与ActiveRecord对象的关系

时间:2014-01-25 00:35:09

标签: ruby activerecord rspec mocking relation

我没有测试Rails应用。只是把它排除在外。

我正在测试连接到相对活动服务器的库,按时间戳限制记录。这些返回的记录随着时间​​的推移而变化,使得测试其他限制更加复杂。我需要删除ActiveRecord::where方法,以便为我创建的对象返回自己的自定义关系,以满足我需要的标准。

这样的东西
relation = double(ActiveRecord::Relation)
relation.stub(:[]).and_return( [MyClass.new(...), MyClass.new(...), ...] )
MyClass.stub(:where).and_return( relation )

是我想要的,但这不起作用。我需要它是ActiveRecord::Relation,因为我需要能够在代码中的对象上调用ActiveRecord::whereActiveRecord::select


修改2014-01-28

在lib / call.rb

class Call < ActiveRecord::Base
  class << self
    def sales start_time, end_time
      restricted_records = records(start_time, end_time, :agent_id)
      #other code
    end

    #other methods

    private

      def records start_time, end_time, *select
        # I'm leaving in commented code so you can see why I want the ActiveRecord::Relation object, not an Array
        calls = Call.where("ts BETWEEN '#{start_time}' AND '#{end_time}'") #.select(select)
        raise calls.inspect
          #.to_a.map(&:serializable_hash).map {|record| symbolize(record)}
      end
  end
end

在spec / call_spec.rb

require 'spec_helper'
require 'call.rb'

describe Call do
  let(:period_start) { Time.now - 60 }
  let(:period_end) { Time.now }

  describe "::sales" do
    before do
      relation = Call.all
      relation.stub(:[]).and_return( [Call.new(queue: "12345")] )
      Call.stub(:where).and_return( relation )
    end

    subject { Call.sales(period_start, period_end) }

    it "restricts results to my custom object" do
      subject
    end
  end
end

测试结果:

RuntimeError:
  #<ActiveRecord::Relation [ #an array containing all the actual Call records, not my object ]>

1 个答案:

答案 0 :(得分:3)

ActiveRecord::Relation是一个类,:[]是该类的实例方法。你正在编写一个类本身的方法,所以它不会被任何Rails代码调用。

如果您希望MyClass.where仅返回:[]存根的关系,则必须首先创建一个Relation实例,如:

relation = MyClass.all
relation.stub(:[]).and_return( [MyClass.new(...), MyClass.new(...), ...] )
MyClass.stub(:where).and_return( relation )

但是,请注意,为了在此上下文中访问您返回的数组,您需要执行以下操作:

MyClass.where("ignored parameters")["ignored parameters"]

此外,如果您随后在where上致电relation,则会返回Relation实例,该实例将不再存在。