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:
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:
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.
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
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.
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.
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.
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.
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.
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
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.