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 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
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
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.