How to fake Time.now?

前端 未结 14 1066
不知归路
不知归路 2020-12-02 11:47

What\'s the best way to set Time.now for the purpose of testing time-sensitive methods in a unit test?

相关标签:
14条回答
  • 2020-12-02 12:29

    I'm using RSpec and I did this: Time.stub!(:now).and_return(2.days.ago) before I call Time.now. In that way I'm able to control the time I used for that particular test case

    0 讨论(0)
  • 2020-12-02 12:35

    Don't forget that Time is merely a constant that refers to a class object. If you're willing to cause a warning, you can always do

    real_time_class = Time
    Time = FakeTimeClass
    # run test
    Time = real_time_class
    
    0 讨论(0)
  • 2020-12-02 12:39

    Had the same issue, I had to fake time for a spec for a specific day and time just did that:

    Time.stub!(:now).and_return(Time.mktime(2014,10,22,5,35,28))        
    

    this will give you:

    2014-10-22 05:35:28 -0700
    
    0 讨论(0)
  • 2020-12-02 12:41

    Do the time-warp

    time-warp is a library that does what you want. It gives you a method that takes a time and a block and anything that happens in the block uses the faked time.

    pretend_now_is(2000,"jan",1,0) do
      Time.now
    end
    
    0 讨论(0)
  • 2020-12-02 12:42

    Depending upon what you are comparing Time.now to, sometimes you can change your fixtures to accomplish the same goal or test the same feature. For example, I had a situation where I needed one thing to happen if some date was in the future and another to happen if it was in the past. What I was able to do was include in my fixtures some embedded ruby (erb):

    future:
        comparing_date: <%= Time.now + 10.years %>
        ...
    
    past:
        comparing_date: <%= Time.now - 10.years %>
        ...
    

    Then in your tests then you choose which one to use to test the different features or actions based upon the time relative to Time.now.

    0 讨论(0)
  • 2020-12-02 12:42

    The recently-released Test::Redef makes this and other fakery easy, even without restructuring the code in a dependency-injection style (especially helpful if you're using other peoples' code.)

    fake_time = Time.at(12345) # ~3:30pm UTC Jan 1 1970
    Test::Redef.rd 'Time.now' => proc { fake_time } do
       assert_equal 12345, Time.now.to_i
    end
    

    However, be careful of other ways to obtain time that this will not fake out (Date.new, a compiled extension that makes its own system call, interfaces to things like external database servers which know current timestamps, etc.) It sounds like the Timecop library above might overcome these limitations.

    Other great uses include testing things like "what happens when I'm trying to use this friendly http client but it decides to raise this an exception instead of returning me a string?" without actually setting up the network conditions which lead to that exception (which may be tricky). It also lets you check the arguments to redef'd functions.

    0 讨论(0)
提交回复
热议问题