RSpec’ing with Time.now

I’m currently writing some RSpec tests that use Time.now.

I want my model to calculate a duration and store the future time in the database. I’ve already specced the calculation of the duration, but I also want to spec that everything gets saved correctly. Here’s my first spec:

it "should do stuff" do
  m = Model.create()
  m.expires_at.should eql(Time.now + some_value)
end

This fails.

It fails because Time.now is quite accurate and some milliseconds have passed between the two calls.

So how do you test this kind of behaviour? Get out your gloves, because we’re going to start stubbing!

What you need to do is stub out Time#now to return a constant value within this test. This way, both calls will use the same Time.now value and thus yield the same result. This in turn makes your test pass (if the saving goes well, of course).

it "should do stuff" do
  @time_now = Time.parse("Feb 24 1981")
  Time.stub!(:now).and_return(@time_now)
 
  m = Model.create()
  m.expires_at.should eql(Time.now + some_value)
end
  • Twitter
  • Digg
  • del.icio.us
  • DZone
  • Reddit
  • email

3 Responses to “RSpec’ing with Time.now”

  1. Or you could pass the current time to Model.create(). I’m starting to dislike all this mocking and stubbing.

  2. The idea is that you test your Model as it is. I don’t think it’s smart to change your Model to accept a Time object just to test it.

    Stubbing and mocking can get ugly and I try to keep it to an absolute minimum. This example, however, works fine and it’s quite clear what you’re doing.

  3. Timecop ( http://github.com/jtrupiano/timecop ) can be particularly handy in these situations. One particularly useful feature is that it mocks Time.now, Date.today and DateTime.now all in one call. It also allows you to distinguish between freezing time (Timecop.freeze) and rebasing time (Timecop.travel). The latter allows Time to continue to move forward.

Leave a Reply