[rspec-users] Strange message expectation behaviour with Time.now in a find condition

Nick Hoffman nick at deadorange.com
Thu Jan 29 14:04:44 EST 2009


On 29/01/2009, at 1:41 PM, David Chelimsky wrote:
> On Thu, Jan 29, 2009 at 12:08 PM, tatyree <todd at snappl.co.uk> wrote:
> Even if this is a bug, it's a pretty obscure one.  It was frustrating
> the hell out of me until I found a workaround, so I thought I'd just
> post the details:
>
> Given a find like this:
>
> def self.find_old
>  User.all(:conditions => ['updated_at <= ?',Time.now - 1.day)
>  ...
>
> Trying to set a message expectation will always fail:
>
> it "should find users" do
>  User.should_receive(:all).with({:conditions => ['updated_at
> <= ?',Time.now - 1.day]})
>  User.find_old
>  ...
>
> with the error:
>  Mock 'Class' expected :all with ({:conditions=>["updated_at <= ?",
> Wed Jan 28 17:59:02 +0000 2009]}) but received it with ({:conditions=>
> ["updated_at <= ?", Wed Jan 28 17:59:02 +0000 2009]})
>
> Expected and received here are identical.
>
> The only workaround I've found (the example here is simplified, but
> the datetime in the model where I discovered the bug is critical and
> so needs to be spec'd) is to wrap the Time call and the expectation in
> another format:
>
> User.all(:conditions => ['updated_at <= ?',(Time.now -
> 1.day).xmlschema])
>
> and
>
> it "should find users" do
>  User.should_receive(:all).with({:conditions => ['updated_at <= ?',
> (Time.now - 1.day).xmlschema]})
>
> I'm on rspec 1.1.12 on rails 2.1.0 and I'm guessing the + in the
> formatted datetime is playing hell with a regexp somewhere.
> Unfortunately, I don't have time to dig in to it myself right now.
>
> I was seeing the same behaviour when I tried hash_including
> (:conditions => ['updated_at <= ?',Time.now - 1.day]) as part of the
> expectation.
>
> The problem is a display problem - the Time objects are actually  
> different by some milliseconds, but you don't see that in the  
> feedback.
>
> Try this:
>
> now = Time.now
> Time.stub!(:now).and_return(now)
>
> Then both calls will return the same object.

You're too fast, David and Aslak!  =P

Todd, I fell prey to the same problem a few months ago. As David and  
Aslak suggested, just stub out Time#now . Eg:

it 'should do something' do
   now = Time.now
   Time.stub!(:now).and_return now
   User.should_receive(:all).with(:conditions => ['updated_at <= ?',  
now - 1.day])
   User.all(:conditions => ['updated_at <= ?', Time.now - 1.day])
end

Cheers,
Nick


More information about the rspec-users mailing list