New Rails 4.1 Travel_to Test Helper

I’ve recently had the good fortune of working on a greenfield Rails app. The app is heavily dependent on times and recurring events (weekly). Naturally, I dragged in the timecop gem to handle freezing time, so my I could properly assert that certain events took place in the tests.

With the release of Rails 4.1, the time stubbing method travel_to was added. This new helper method forces the current time to whatever you specify, allowing you to make asserts against a historical time, or week in my case.

The Test

Timecop performed valiantly and did more than I ever needed (I generally only used the freeze method). However, dragging in another gem was the last thing I wanted to do for something relatively simple.

Prior to utilizing the changes in Rails 4.1, one of my tests looked like:

test "sends reminders on tuesday for those scheduled on wednesday" do
  Timecop.freeze Chronic.parse("4/15/14") do
    Reminders::Checkin.new.email
    assert_equal 3, ActionMailer::Base.deliveries.size
  end
end

Note: Chronic is a gem that helps create dates/times by using standard language.

Rails 4.1

I think I first heard about some additional testing methods from my friend Eric Steele. He mentioned them in one of our various conversations about testing (he’s writing a book titled What Do I Test?).

Like many, I looked over the release notes for Rails 4.1 and features like Spring, secrets, ActionMailer previews, and ActiveRecord enums jumped out at me.

Towards the bottom, though, was a feature barely mentioned or written about:

"Test helper addition in Rails 4.1"

The TimeHelpers test module adds the travel_to and travel_back methods to assist in stubbing Time.now and Date.today.

Updated Tests

Using the travel_to method with the example above results in the following:

test "sends reminders on tuesday for those scheduled on wednesday" do
  travel_to Chronic.parse("4/15/14") do
    Reminders::Checkin.new.email
    assert_equal 3, ActionMailer::Base.deliveries.size
  end
end

Because I’m using the travel_to method with a block, there’s no need to use the travel_back method to reset time back to the current time. Supply a block automatically calls travel_back.

While the change doesn’t look significant, it removed my need for the Timecop gem entirely.

Additionally, the same test could be written as:

test "sends reminders on tuesday for those scheduled on wednesday" do
  travel_to Chronic.parse("4/15/14")
  Reminders::Checkin.new.email
  assert_equal 3, ActionMailer::Base.deliveries.size
  travel_back
end

or with setup and teardown:

def setup
  travel_to Chronic.parse("4/15/14")
end

test "sends reminders on tuesday for those scheduled on wednesday" do
  Reminders::Checkin.new.email
  assert_equal 3, ActionMailer::Base.deliveries.size
end

def teardown
  travel_back
end

Summary

Rails is well-known for conventions. travel_to is a great addition to the framework that would’ve otherwise required dragging in additional dependencies.

Next time you look at the release notes for a project, don’t skip over the less featured functionality. For all you know, it could be something that saves you time and frustration that commonly occurs in your projects.