ActiveRecord オブジェクトとのスタブ ActiveRecord::Relation
概要
Rails アプリをテストしているわけではありません。それを邪魔にならないようにするだけです。
タイムスタンプによってレコードを制限し、比較的アクティブなサーバーに接続するライブラリをテストしています。これらの返されたレコードは時間の経過とともに変化するため、他の制限のテストがより複雑になります。必要な条件を満たすために作成したオブジェクトとの独自のカスタム関係を返すには、ActiveRecord::where メソッドをスタブアウトする必要があります。
何かのようなもの
relation = double(ActiveRecord::Relation)
relation.stub(:[]).and_return( [MyClass.new(...), MyClass.new(...), ...] )
MyClass.stub(:where).and_return( relation )
それが私が望むことですが、それはうまくいきません。コード内のオブジェクトに対して ActiveRecord::where と ActiveRecord::select を呼び出すことができる必要があるため、これを ActiveRecord::Relation にする必要があります。
編集 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 ]>
解決策
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"]
さらに、その後、relation で where を呼び出すと、スタブ化されなくなる Relation の新しいインスタンスが返されます。