我想为应用程序创建测试数据,并且有很多time_at
属性被跟踪,太多而无法以可维护的方式覆盖。我在想的是,我可以在Ruby中更改基本参考时间变量吗?
这样可以将created_at
,updated_at
,last_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
有办法做到这一点吗?
答案 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)