RSpec and stubbing parameters for a named scope
I'm try to write a spec for a named scope which is date dependent.
The spec:
it "should return 6 months of documents" do
Date.stub!(:today).and_return(Date.new(2005, 03, 03))
doc_1 = Factory.create(:document, :date => '2005-01-01')
Document.past_six_months.should == [doc_1]
end
The named scope in the Document model:
named_scope :past_six_months,
:conditions => ['date > ? AND date < ?', Date.today - 6.months, Date.today]
The spec fails with an empty array, and the query in test.log shows why:
SELECT * FROM "documents" WHERE (date > '2009-11-11' AND date < '2010-05-11')
i.e. it appears to be ignoring my stubbed Date method.
However, if I use a class method instead of a named scope then it passes:
def self.past_six_months
find(:all, :conditions => ['date > ? AND date < ?', Date.today - 6.months, Date.today])
end
I would rather use the named scope approach but I don't understand why it isn't working.
===
In reply to @speicher:
Thanks, but Timecop doesn't seem to help here.
it "should return 6 months of documents" do
d = Date.new(2005, 03, 01)
Timecop.travel(开发者_如何学编程d)
doc_1 = Factory.create(:document, :date => '2005-01-01')
Document.past_six_months.should == [doc_1]
end
Still passes for the class method approach but not for the named scope.
I suspect that named_scope is doing some kind of manipulation on the passed conditions before actually evaluating them, meaning that Date.today is never called directly.
I think the problem is that Date.today is not being computed at run-time, but when the model is first read by rails. Try enclosing it in a lambda:
named_scope :past_six_months, lambda { {:conditions => ['date > ? AND date < ?', Date.today - 6.months, Date.today] } }
Save yourself some headaches and use the Timecop gem to fake a date or time.
精彩评论