Trouble testing timestamps

Since I’ve been encouraging myself to write more and better unit tests, I have encountered a troubling obstacle when writing tests to cover timestamp creation and updating. Let’s say I have a Record class which has a modification and creation timestamp. The ctime instance variable is created when a Record is instatiated and mtime is updated whenever the Record is updated. So, my test looks like this:

def test_ctime
  record = Record.new
  assert_equal(Time.now, record.ctime)
end

This failed because, believe it or not, the timers have too high a resolution! In fact, even evaluating (with the help of irb) Time.now == Time.now is false. This is evident by evaluating 5.times { puts Time.now.to_f } and seeing how the output differs by a tiny amount with each iteration.

I response to this, I decided to generalize and adapt my assertion to accept a diminished resolution with a tolerance of one second. assert_equal(Time.now.sec, record.ctime.to_i). This is still imprecise but it gets my point across.

I had resigned myself to accept this troublesome compromise until I went to write the test for mtime. My test for mtime updating looked like this:

def test_mtime_update
  record = Record.new
  record.update
  assert_operator(Time.now, :>, record.mtime)
end

I feel like I am compromising because I can’t make accurate comparisons and can’t figure out how to do this properly. It seems impossible and I don’t feel as if I have adequate coverage because I can’t verify timestampt at all. Perhaps I am doing something obviously wrong or testing for the wrong things. To make myself feel better I added an assert_instance_of(Time, record.ctime) and the same thing for mtime. Still, this has given me much frustration and I can’t imagine no one else has encountered this before.

I’m writing this as part of a multithreaded application where timestamp resolution could be quite crucial and I see my tests failing to give me proper coverage. Help?

    • Ben
    • February 25th, 2009
  1. Sounds like what you need to be doing is stubbing. It’s kind of silly to be trying to test that a constantly changing value is equal to a fixed one.

    Checkout mocha – http://mocha.rubyforge.org – it’s a stubbing library that makes testing things much easier, especially in this regard.

    For example, you’d be able to do something like the below, assuming that Record.new sets ctime to be the value of Time.now:

    def test_ctime
    test_time = Time.now
    Time.stubs(:new).returns(test_time)
    record = Record.new
    assert_equal(test_time, record.ctime)
    end

  1. No trackbacks yet.