Mock today


#1

In some of my unit tests, I find the need to set today to a different
value than the actual today. For example, to test the model method
“balance_of_today”, which takes no argument, I want to have Date.today
be a specific date for the purpose of testing. In other words, I want
to do something like this:

mock_today(Date.new(2008, 2, 1)) do
… test code…
end

My implementation for mock_today is:

def mock_today(date)
$_mock_test_date = date

Date.class_eval do
  class <<self
    alias original_today today
  end

  def self.today
    $_mock_test_date
  end
end

yield

Date.class_eval do
  class <<self
    alias today original_today
  end
end

end

So my questions are:

  1. Is it a good idea to mock Date.today?

  2. Can my implementation of mock_today be improved? I’m particularly
    worried about of the use of global variable, and of class_eval, since
    I heard class_eval is becoming outdated as Ruby 1.9 is coming out.


#2

On Nov 19, 8:20 pm, Eric LIn removed_email_address@domain.invalid wrote:

My implementation for mock_today is:
$_mock_test_date
end

So my questions are:

  1. Is it a good idea to mock Date.today?

  2. Can my implementation of mock_today be improved? I’m particularly
    worried about of the use of global variable, and of class_eval, since
    I heard class_eval is becoming outdated as Ruby 1.9 is coming out.

I occasionally “timetravel” by overriding Time.now (and Date.today
calls Time.now eventually).
It goes a little like this

class Time
cattr_accessor :frozen_now
self.frozen_now = nil
class << self
def now_with_freeze
if @@frozen_now
@@frozen_now
else
now_without_freeze
end
end
alias_method_chain :now, :freeze
end
end

Then you freeze by doing Time.frozen_now = … and unfreeze by setting
it back to nil. You could easily refactor this to have a block like
syntax.

Fred


#3

On Nov 19, 2008, at 3:37 PM, Frederick C. wrote:

end

  end

I heard class_eval is becoming outdated as Ruby 1.9 is coming out.
if @@frozen_now
it back to nil. You could easily refactor this to have a block like
syntax.

Fred

Or use flexmock:

require ‘rubygems’
gem :flexmock
require ‘flexmock/test_unit’

then in your test

 stopped_clock = Date.new(2008, 2, 1)
 flexmock(Date).should_receive(:today).returns(stopped_clock)

-Rob

Rob B. http://agileconsultingllc.com
removed_email_address@domain.invalid


#4

Thanks, both of these are good suggestions. I will look into them.

On Nov 19, 12:43 pm, Rob B. removed_email_address@domain.invalid