A friend of a friend has trouble testing timestamps. I tried replying there, but don’t think my answer got through so here it is.

The short answer: all time operations should not use the wall clock, but a system time object that you create. In production, the system time object returns wall clock time. In testing, you replace/mock/modify it so that it uses the time you give it. In other words, it becomes a clock that you can freeze and re-set whenever you need to.

Here is an example SystemClock class in Ruby. All of your classes should use this class to get the current date and time instead of using the Time or Date classes directly.

# Keeper of the current system time. This class is sometimes overridden
# during testing to return different times.
class SystemClock

  def self.date
    Date.today
  end

  def self.time
    Time.new
  end

end

Here is the mock used during testing. You can set the time using this mock object and it will not change until it is set again.

# This mock lets you set the system date and time during testing. For
# example, to set the date to tomorrow,
#
# A few examples of use:
#
#   SystemClock.date = Date.today + 1 # Time also set: to tomorrow 9:10:11 am
#   SystemClock.date = nil            # Go back to using system date and time
#   SystemClock.date = Date.civil(2006, 4, 15)
#   SystemClock.time = Time.local(2006, 3, 2, 8, 42, 42) # Date changed, too
#
# When you set the date, the time is set to 9:10:11 am of the same day,
# local time. When you set the time, the date is set to the same day.

require 'models/system_clock'

class SystemClock

  @mock_date = nil
  @mock_time = nil

  def self.reset
    @mock_date = nil
    @mock_time = nil
  end

  def self.date=(date)
    @mock_date = date
    @mock_time = date == nil ? nil :
      Time.local(date.year, date.month, date.day, 9, 10, 11)
  end

  def self.time=(time)
    @mock_time = time
    @mock_date = time == nil ? nil :
      Date.civil(time.year, time.month, time.day)
  end

  def self.date
    @mock_date || Date.today
  end

  def self.time
    @mock_time || Time.new
  end

end

So in your normal production code you get the current time by calling =SystemClock.time= instead of =Time.now=. In your test code, you’d do something like this:

# Make sure to include the mock class
SystemClock.time = Time.now # Or any arbitrary time
thing = Thing.new           # Uses SystemClock to set created_at attribute
assert_equal SystemClock.time, thing.created_at