TimeWithZone & Time.zone.now 集成测试失败

TimeWithZone & Time.zone.now integration test fails

在控制器方法中,当向用户发送激活电子邮件时,我将用户的变量 activation_sent_at 设置为等于 Time.zone.now。在开发服务器上这似乎有效(尽管我的应用程序中的时间表达式比我计算机的本地时间晚 2 小时)。

我想包括一个集成测试来测试 activation_sent_at 是否确实设置正确。所以我包括了这一行:

assert_equal @user.activation_sent_at, Time.zone.now

但是,这会产生错误:

No visible difference in the ActiveSupport::TimeWithZone#inspect output.
You should look at the implementation of #== on ActiveSupport::TimeWithZone or its members.

我认为它建议在我的测试中对 Time.zone.now 使用另一个表达式。我查看了不同的来源,包括 http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html,但我不确定在这里做什么。任何可能导致此错误的建议?

附加信息: 添加 puts Time.zone.nowputs @stakeholder.activation_sent_at 确认两者相等。不确定是什么生成了 failure/error.

问题是这两个日期非常接近但不相同。您可以使用 assert_in_delta

assert_in_delta @user.activation_sent_at, Time.zone.now, 1.second

对于 RSpec,类似的方法是使用 be_within:

expect(@user.activation_sent_at).to be_within(1.second).of Time.zone.now

问题是你们的时间很接近但不完全相等。它们可能相差几分之一秒。

此类问题的一个解决方案是名为 timecop 的测试 gem。它使您能够模拟 Time.now,以便它暂时 return 一个您可以用于比较的特定值。

原因是因为 Time.nowTime.zone.now 包含毫秒(当您执行简单的 put 打印时间时它不显示毫秒)。但是,当您将时间戳保存在数据库中时,除非将 db 字段配置为存储毫秒,否则这些毫秒可能会丢失。因此,当您从数据库中读取值时,它不会包括毫秒,因此时间略有不同。

一种解决方案是从 Time.now 中删除毫秒。你可以这样做 Time.now.change(usec: 0)。这应该可以修复测试中的错误。