覆盖Ruby认为Time.now中的当前时间?

时间:2010-12-30 20:10:11

标签: ruby-on-rails ruby

我想为应用程序创建测试数据,并且有很多time_at属性被跟踪,太多而无法以可维护的方式覆盖。我在想的是,我可以在Ruby中更改基本参考时间变量吗?

这样可以将created_atupdated_atlast_login_at等设置为人工时间,因此我可以在测试中执行此操作:

Date.today #=> Thu, 30 Dec 2010
Time.system_time_offset = 1.week.ago # made up
Date.today #=> Thu, 23 Dec 2010
Time.now   #=> Thu Dec 23 14:08:38 -0600 2010

user_1 = User.create!
user_1.created_at #=> Thu Dec 23 14:08:38 -0600 2010

Time.reset_system_time # made up

user_2 = User.create!
user_1.created_at #=> Thu Dec 30 14:08:38 -0600 2010

有办法做到这一点吗?

5 个答案:

答案 0 :(得分:7)

您可以使用Mocha在测试期间更改Time.now的返回值:

Time.stubs(:now).returns(Time.now - 1.day)

答案 1 :(得分:5)

一个很好的宝石是Timecop:https://github.com/travisjeffery/timecop 你可以很容易地冻结时间或改变时间(当它继续前进时)。

实施例

Time.now
# => 2014-03-14 13:17:02 -0400
Timecop.travel 2.hours.ago
Time.now
# => 2014-03-14 11:17:04 -0400

它比mocha解决方案更好,因为所有时间函数都会受到同等影响,所以你不会有一个测试,其中Time.now返回的东西与DateTime.now不同

它还比另一个答案中建议的时间扭曲宝石更新。

答案 2 :(得分:3)

我使用timewarp gem来做这类事情。您只需将代码放在pretend_now_is(时间)块中,内部代码将被执行,就像实际时间一样。

http://github.com/harvesthq/time-warp

这是一个例子

def test_should_find_company_needing_reminded_today
  pretend_now_is(Time.utc(2008,"jul",24,20)) do #=> Thu Jul 24 20:00:00 UTC 2008
    @company.reminder_day = 'Thursday'
    @company.save
    companies = Company.find_companies_needing_reminded_today
    assert_equal true, companies.include?(@company)
  end
end

答案 3 :(得分:1)

老实说,我通常会编写当前时间的测试来检查时间戳是否在合理范围内。即,检查时间戳是否大于1.minute.ago。更改系统时钟可能会产生各种不可预测的副作用,因此您不希望这样做。您可以跟踪Ruby中访问当前时间的所有位置(虽然我认为大多数方法只使用Time.now)并对它们进行猴子修补以进行测试,但我可能仍然更喜欢只检查时间戳在理智的范围内。

答案 4 :(得分:1)

也可能(yuck)monkeypatch时间:

$start = Time.now - 86400 # this time yesterday

class Time
  class << Time
    def new
      $start
    end
    def now
      Time.new
    end
  end
end

puts(Time.now)
puts($start)