Strange message expectation behaviour with Time.now in a find condition

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.

Thanks,
Todd

On Thu, Jan 29, 2009 at 12:08 PM, tatyree [email protected] wrote:

Trying to set a message expectation will always fail:
[“updated_at <= ?”, Wed Jan 28 17:59:02 +0000 2009]})

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.

On Thu, Jan 29, 2009 at 7:08 PM, tatyree [email protected] wrote:

Trying to set a message expectation will always fail:
[“updated_at <= ?”, Wed Jan 28 17:59:02 +0000 2009]})

Expected and received here are identical.

No they are not. They are milliseconds apart.

You should always stub Time.now in tests.

Aslak

On 29/01/2009, at 1:41 PM, David C. wrote:

Wed Jan 28 17:59:02 +0000 2009]}) but received it with ({:conditions=>
1.day).xmlschema])

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

On Thu, Jan 29, 2009 at 10:41 AM, David C. [email protected]
wrote:

def self.find_old

another format:
I’m on rspec 1.1.12 on rails 2.1.0 and I’m guessing the + in the
now = Time.now
Time.stub!(:now).and_return(now)
Then both calls will return the same object.

What David, Aslak & Nick said.

btw…

~:$ irb

Time.now == Time.now
=> false

Pat

Thanks for that everyone! Henceforth I shall always endeavour to stop
the flow of time in all of my specs!

Avdi G. wrote a blog post about why he doesn’t stub Time.now and
instead
always injects a clock into his objects. I disagreed, but I can’t seem
to
find the article now.

///ark

On Fri, Jan 30, 2009 at 9:17 AM, Mark W. [email protected] wrote:

Avdi G. wrote a blog post about why he doesn’t stub Time.now and instead
always injects a clock into his objects. I disagreed, but I can’t seem to
find the article now.

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/297660

On Fri, Jan 30, 2009 at 7:38 AM, David C.
[email protected]wrote:

On Fri, Jan 30, 2009 at 9:17 AM, Mark W. [email protected] wrote:

Avdi G. wrote a blog post about why he doesn’t stub Time.now and
instead
always injects a clock into his objects. I disagreed, but I can’t seem to
find the article now.

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/297660

Yeah, I saw that, but he laid out his case in greater depth in a blog
post
(i know because I posted a comment disagreeing with it!).

The interesting thing is that Avdi says that stubbing Time.now has
broken
some of his tests in the past because of other code (like RSpec) that
calls
it. I can’t say I’ve ever run into that myself, but it bears keeping in
mind.

///ark

On Fri, Jan 30, 2009 at 9:05 AM, Mark W. [email protected] wrote:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/297660

Yeah, I saw that, but he laid out his case in greater depth in a blog post
(i know because I posted a comment disagreeing with it!).

The interesting thing is that Avdi says that stubbing Time.now has broken
some of his tests in the past because of other code (like RSpec) that calls
it. I can’t say I’ve ever run into that myself, but it bears keeping in
mind.

I think that using a custom Clock class can be very useful. However,
it can cause confusion in Rails apps, because AR uses Time.now for
created_at and updated_at. You’d have to keep specific track of when
you meant to use Clock and when you wanted to control Time, and to me
it’s just not worth it.

Pat