Little ruby libraries - Testing with Timecop

When it comes to little known rubygems that help with my testing I’m a massive fan of the relatively unknown Timecop. It’s a well written, highly focused, gem that lets you control and manipulate the date and time returned by a number of ruby methods. In specs where testing requires certainty of ‘now’ it’s become my favoured first stop.

The puppet deprecate function is a good example of when I’ve needed this functionality. The spec scenarios should exercise a resource with the time set to before and after the deprecation time in separate tests. The two obvious options are to hard code the dates, which won’t work here as we’re black box testing the function or mocking the calls, something Timecop excels at and saves you writing yourself.

require 'timecop'

# explicitly set the date.
Timecop.freeze(Time.local('2015-01-24'))

...
  # success: we've explicitly set the date above to be before 2015-01-25
  # so this resource hasn't been deprecated
  should run.with_params('2015-01-25', 'Remove Foo at the end of the contract.')
...
  # failure: we're using a date older than that set in the freeze above
  # so we now deprecate the resource
  should run.with_params('2015-01-20', 'Trigger expiry')
...

# reset the time to the real now
Timecop.return

This allows us to pick an absolute point in time and use literal strings in our tests that relate to the point we’ve picked. No more intermediate variables with manually manipulated date objects to ensure we’re 7 days in the future or 30 days in the past. Removing this boilerplate code itself was a win for me. If you need to ensure all your specs run with the same time set you can call the freeze and return in the before and after methods.

before do
  # all tests will have this as their time
  Timecop.freeze(Time.local(1990))
end

after do
  # return to normal time after the tests have run
  Timecop.return
end

I’ve shown the basic, and for me most commonly used functionality above, but there are a few helper methods that elevate Timecop from “I could quickly write that myself” to “this deserves a place in my gemfile. The ability to freeze time in the future with a simple Timecop.freeze(Date.today + 7) is handy, the auto-return time to normal block syntax is pure user experience refinement but the Timecop.scale function, that lets you define how much time passes for every real second, isn’t something you need every day, but when you do you’ll be very glad you don’t have to write it yourself.