【问题标题】:Override what Ruby thinks is the current time in Time.now?覆盖 Ruby 认为 Time.now 中的当前时间?
【发布时间】:2011-06-01 17:47:42
【问题描述】:

我想为应用程序创建测试数据,并且有很多 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

有没有办法做到这一点?

【问题讨论】:

标签: ruby-on-rails ruby


【解决方案1】:

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

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

【讨论】:

  • RSpec: Time.stub(:now).and_return(Time.now - 1.day)
【解决方案2】:

一个很好的宝石是 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 不同的地方进行测试

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

【讨论】:

    【解决方案3】:

    我将时间扭曲宝石用于此类事情。您只需将您的代码放在一个假装_now_is(time) 块中,里面的代码就会像实际时间一样执行。

    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
    

    【讨论】:

    • 这会更好,因为它也会影响Date.today
    【解决方案4】:

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

    【讨论】:

    • +1 "更改系统时钟可能会产生各种不可预知的副作用"。绝对。
    【解决方案5】:

    也可以(恶心)猴子补丁时间:

    $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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-17
      • 1970-01-01
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-14
      • 1970-01-01
      相关资源
      最近更新 更多