9

I have an assertion in a test that looks like this:

assert_equals object.sent_at, Time.now

When I run this test, I keep getting an error that looks like this

--- expected +++ actual @@ -1 +1 @@ -Fri, 04 Mar 2016 18:57:47 UTC +00:00 +Fri, 04 Mar 2016

I've tried a few combinations to make this test pass.

My actual code updates the sent_at value with a Time.now but its not quite in the perfect format. It is close but not enough to pass. How can I make this test pass.

Here are some combinations I've tried in my assertions:

Time.now.utc Date.today Time.now

and a lot of to_time , to_datetime etc. How can I make the test pass?

Dan Rubio
  • 4,709
  • 10
  • 49
  • 106
  • It seems `object.sent_at` is returning a `Date`, no time is shown for your 'actual' result. So I don't think testing against a `Time` object would be the right approach. If you did `assert_equals object.sent_at.to_db, Date.today` does that help? I'm tempted to say `assert_equals object.sent_at, Date.today` should be good enough, but it appears you may have tried that already. – SRod Mar 04 '16 at 19:48

4 Answers4

13

Old but still valid... The output shows that the comparison is against UTC which would be Time.current

At this time you would probably use:

assert_in_delta object.sent_at, Time.current, 1

To tolerate <1 second difference

estani
  • 24,254
  • 2
  • 93
  • 76
6

Using Time#to_i isn't the best solution. If the task you are running takes more than a second the comparison would fail. Even if your task is fast enough, this comparison would fail:

time = Time.now # 2018-04-18 3:00:00.990
# after 20ms
assert_equal Time.now.to_i, time.to_i # Fails

Time.now would be 2018-04-18 3:00:01.010 and to_i would give you 2018-04-18 3:00:01 and time was 2018-04-18 3:00:00.990 and to_i: 2018-04-18 3:00:00. So the assert fails. So, sometimes the test would pass and others would fail, depending on when (in miliseconds) it starts.

The better solution is to freeze the Time. You could use a gem like Timecop or write your own code, like (using MiniTest):

current_time = Time.now
# You need Mocha gem to use #stubs
Time.stubs(:now).returns(current_time)

You can also use a block, so that after the block the clock is back to normal

# For this you don't need Mocha
Time.stub :now, current_time do   # stub goes away once the block is done
  assert your_task
end
  • 1
    Yup. Just got that same issue! Thanks for timecop. It's been a lifesaver. One thing, is "stubs" part of TIme? I was having issues. I ended up using `.freeze` instead – Jose A Jul 11 '18 at 17:50
  • 1
    #stubs is actually from Mocha (I'll fix the answer), which is awesome btw. Minitest has a method called #stub, which is the second option in my answer – Gorodscy Fernando Jul 12 '18 at 17:58
  • Thank you :D I used Timecop and it was a lifesaver! Simple to use and works flawlessly ;) – Jose A Jul 13 '18 at 04:56
  • In the second example, `current_time` may as well be replaced with `Time.now` so it would work anywhere. – Masa Sakano Oct 12 '18 at 18:53
4

I think it is easiest to use Time#to_i to compare the time in seconds.

assert_equals object.sent_at.to_i, Time.now.to_i # seconds

Jack Collins
  • 1,145
  • 10
  • 21
0

You can use Timecop gem: https://github.com/travisjeffery/timecop

def test
  Timecop.freeze do # Freeze current time
    Time.now # some value
    ...
    Time.now # The same value as previous
  end
end

Dmitry Ukolov
  • 658
  • 7
  • 10