Test code for the module that receives the current time.

What is the best way to write unit test for code that gets the current time? For example, some object can be created only on business days, other objects take the current time into account when checking permissions to perform certain actions, etc.

I think I should mock Date.today and Time.now. Is this the right approach?

Update: both solutions (a) Time.is and (b) Time.stubs (: now) .returns (t) work. (a) a very good approach, but (b) the solution will be more consistent with another test code.

In this question, the author asks for a general solution. For Ruby, in my version, the two solutions above are simpler and therefore better than retrieving code that receives the current date / time.

BTW I recommend using Chronic to get the required time, for example.

require 'Chronic'    
mon = Chronic.parse("next week monday")
Time.stubs(:now).returns(mon)
+5
source share
5 answers

Mocking Time.now or Date.today seem simple enough, look something like this:

require 'rubygems'
require 'test/unit'
require 'mocha'

class MyClass

  def foo
    Time.now
  end

end

class MyTest < Test::Unit::TestCase

  def test_foo
    assert true
    t = Time.now
    Time.expects(:now).returns(t)
    assert_equal t, MyClass.new.foo
  end

end
+3
source

The following is Jay Field Thoughts . This allows you to override Time.nowfor the duration of the block.

require 'time'

class Time
  def self.metaclass
    class << self; self; end
  end

  def self.is(point_in_time)
    new_time = case point_in_time
      when String then Time.parse(point_in_time)
      when Time then point_in_time
      else raise ArgumentError.new("argument should be a string or time instance")
    end
    class << self
      alias old_now now
    end
    metaclass.class_eval do
      define_method :now do
        new_time
      end
    end
    yield
    class << self
      alias now old_now
      undef old_now
    end
  end
end

Time.is(Time.now) do
  Time.now # => Tue Nov 13 19:31:46 -0500 2007
  sleep 2
  Time.now # => Tue Nov 13 19:31:46 -0500 2007
end

Time.is("10/05/2006") do
  Time.now # => Thu Oct 05 00:00:00 -0400 2006
  sleep 2
  Time.now # => Thu Oct 05 00:00:00 -0400 2006
end
+6
source

ITimeProvider () , , , mock, .

+3

, , , . , / , , . , , , Date.today Time.now, .

. ITimeProvider, ..., , -, , -.

+3

Creating an ITimeProvider object as a dependency is better than passing time, because it follows the Do Not Repeat Yourself principle.

Somewhere in your working code, something should get the current time. You can take the date generation code outside of your testing scope or you can have one easily verifiable object that can be everywhere.

0
source

All Articles