How to fake Time.now?

前端 未结 14 1138
不知归路
不知归路 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:22

    This kind of works and allows for nesting:

    class Time
      class << self
        attr_accessor :stack, :depth
      end
    
      def self.warp(time)
    
        Time.stack ||= [] 
        Time.depth ||= -1 
        Time.depth += 1
        Time.stack.push time
    
        if Time.depth == 0 
          class << self    
              alias_method :real_now, :now  
              alias_method :real_new, :new
    
              define_method :now do
                stack[depth] 
              end
    
              define_method :new do 
                now 
              end
          end 
        end 
    
        yield
    
        Time.depth -= 1
        Time.stack.pop 
    
        class << self 
          if Time.depth < 0 
            alias_method :new, :real_new
            alias_method :now, :real_now
            remove_method :real_new
            remove_method :real_now 
          end
        end
    
      end
    end
    

    It could be slightly improved by undefing the stack and depth accessors at the end

    Usage:

    time1 = 2.days.ago
    time2 = 5.months.ago
    Time.warp(time1) do 
    
      Time.real_now.should_not == Time.now
    
      Time.now.should == time1 
      Time.warp(time2) do 
        Time.now.should == time2
      end 
      Time.now.should == time1
    end
    
    Time.now.should_not == time1 
    Time.now.should_not be_nil
    

提交回复
热议问题