Overriding Time.now

Hello!

I have a unit test where I need to simulate a different system time.

Hence I need Time.now to return a different time than now, say, now + 1
month

How can I do this?

I tried aliasing Time now, but I don't know how to alias class methods.

class Time
alias_method 'self.original_now', 'self.now'
end

How can I alias this --or-- is there any better way to simulate a different
time on calling Time.now?

Tips and ideas are greatly appreciated,
Rob

Hi

class Time
    class << self
        alias_method :n, :now
    end
end

hope that helps
Cheers
Robert

···

On 5/24/06, Robert MannI <robmnl@gmail.com> wrote:

Hello!

I have a unit test where I need to simulate a different system time.

Hence I need Time.now to return a different time than now, say, now + 1
month

How can I do this?

I tried aliasing Time now, but I don't know how to alias class methods.

class Time
alias_method 'self.original_now', 'self.now'
end

How can I alias this --or-- is there any better way to simulate a
different
time on calling Time.now?

Tips and ideas are greatly appreciated,
Rob

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

Thanks alot Robert, that'll do it

Rob

···

On 5/24/06, Robert Dober <robert.dober@gmail.com> wrote:

On 5/24/06, Robert MannI <robmnl@gmail.com> wrote:
>
> Hello!
>
> I have a unit test where I need to simulate a different system time.
>
> Hence I need Time.now to return a different time than now, say, now + 1
> month
>
> How can I do this?
>
> I tried aliasing Time now, but I don't know how to alias class methods.
>
> class Time
> alias_method 'self.original_now', 'self.now'
> end
>
> How can I alias this --or-- is there any better way to simulate a
> different
> time on calling Time.now?
>
> Tips and ideas are greatly appreciated,
> Rob

Hi

class Time
    class << self
        alias_method :n, :now
    end
end

hope that helps
Cheers
Robert

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

One caution: I did what Robert suggested a while back. It works perfectly, but does wreak havoc with Test::Unit and rake test times reporting. Tests can appear to finish before they've started, etc. I ended up creating a CurrentTime class:

class CurrentTime
  @@now = nil

  def now
    @@now || Time.now
  end

  def now=(new_time)
    @@now = new_time
  end
end

I changed my code to use CurrentTime.now instead of Time.now. Test::Unit, rake and friends still use Time.now, so they don't get messed up. In my unit test I mock out the time by calling CurrentTime.now=. Crude but it works.

Steve

···

-----Original Message-----
From: Robert MannI [mailto:robmnl@gmail.com]
Sent: Wednesday, May 24, 2006 9:37 AM
To: ruby-talk ML
Subject: Re: Overriding Time.now

Thanks alot Robert, that'll do it

Rob

On 5/24/06, Robert Dober <robert.dober@gmail.com> wrote:

On 5/24/06, Robert MannI <robmnl@gmail.com> wrote:
>
> Hello!
>
> I have a unit test where I need to simulate a different system time.
>
> Hence I need Time.now to return a different time than now, say, now
> + 1 month
>
> How can I do this?
>
> I tried aliasing Time now, but I don't know how to alias class methods.
>
> class Time
> alias_method 'self.original_now', 'self.now'
> end
>
> How can I alias this --or-- is there any better way to simulate a
> different time on calling Time.now?
>
>
> Tips and ideas are greatly appreciated, Rob

Hi

class Time
    class << self
        alias_method :n, :now
    end
end

hope that helps
Cheers
Robert

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

One caution: I did what Robert suggested a while back. It works
perfectly, but does wreak havoc with Test::Unit and rake test times
reporting. Tests can appear to finish before they've started, etc. I ended
up creating a CurrentTime class:

class CurrentTime
  @@now = nil

  def now
    @@now || Time.now
  end

  def now=(new_time)
    @@now = new_time
  end
end

I changed my code to use CurrentTime.now instead of Time.now. Test::Unit,
rake and friends still use Time.now, so they don't get messed up. In my
unit test I mock out the time by calling CurrentTime.now=. Crude but it
works.

Yup you have to change the code to be tested, not the best idea.
I guess you can avoid this by redefining now only in the class to be tested,
please note I did not hang anybody (by not redefining Time.now) just gave
you the rope to hang yourself (by redefining Time.now).
Now (pun intended) I believe that you can redefine Time.now in the scope
where you need it without interfering with Test::Unit, well you are still
administring the code you test somehow.
Neverheless that might be the cleanest approach, I would be glad to have a
better one suggested though.

Cheers
Robert

Steve

···

On 5/24/06, Molitor, Stephen L <Stephen.L.Molitor@erac.com> wrote:

-----Original Message-----
From: Robert MannI [mailto:robmnl@gmail.com]
Sent: Wednesday, May 24, 2006 9:37 AM
To: ruby-talk ML
Subject: Re: Overriding Time.now

Thanks alot Robert, that'll do it

Rob

On 5/24/06, Robert Dober <robert.dober@gmail.com> wrote:
>
> On 5/24/06, Robert MannI <robmnl@gmail.com> wrote:
> >
> > Hello!
> >
> > I have a unit test where I need to simulate a different system time.
> >
> > Hence I need Time.now to return a different time than now, say, now
> > + 1 month
> >
> > How can I do this?
> >
> > I tried aliasing Time now, but I don't know how to alias class
methods.
> >
> > class Time
> > alias_method 'self.original_now', 'self.now'
> > end
> >
> > How can I alias this --or-- is there any better way to simulate a
> > different time on calling Time.now?
> >
> > Tips and ideas are greatly appreciated, Rob
>
> Hi
>
> class Time
> class << self
> alias_method :n, :now
> end
> end
>
> hope that helps
> Cheers
> Robert
>
> --
> Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
> concerne l'univers, je n'en ai pas acquis la certitude absolue.
>
> - Albert Einstein
>

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

I believe that you can redefine Time.now in the scope where you need
it without interfering with Test::Unit

There's only one instance of the Time class object, and any changes you make to it are in effect 'global'. At least in Ruby 1.8. I understand there's some talk of adding namespaces or something to be able to make modifications and extensions to classes only apply in a certain scope in Ruby 2.0.

Steve

···

-----Original Message-----
From: Robert Dober [mailto:robert.dober@gmail.com]
Sent: Wednesday, May 24, 2006 10:19 AM
To: ruby-talk ML
Subject: Re: Overriding Time.now

On 5/24/06, Molitor, Stephen L <Stephen.L.Molitor@erac.com> wrote:

One caution: I did what Robert suggested a while back. It works
perfectly, but does wreak havoc with Test::Unit and rake test times
reporting. Tests can appear to finish before they've started, etc. I
ended up creating a CurrentTime class:

class CurrentTime
  @@now = nil

  def now
    @@now || Time.now
  end

  def now=(new_time)
    @@now = new_time
  end
end

I changed my code to use CurrentTime.now instead of Time.now.
Test::Unit, rake and friends still use Time.now, so they don't get
messed up. In my unit test I mock out the time by calling
CurrentTime.now=. Crude but it works.

Yup you have to change the code to be tested, not the best idea.
I guess you can avoid this by redefining now only in the class to be tested, please note I did not hang anybody (by not redefining Time.now) just gave you the rope to hang yourself (by redefining Time.now).
Now (pun intended) I believe that you can redefine Time.now in the scope where you need it without interfering with Test::Unit, well you are still administring the code you test somehow.
Neverheless that might be the cleanest approach, I would be glad to have a better one suggested though.

Cheers
Robert

Steve

-----Original Message-----
From: Robert MannI [mailto:robmnl@gmail.com]
Sent: Wednesday, May 24, 2006 9:37 AM
To: ruby-talk ML
Subject: Re: Overriding Time.now

Thanks alot Robert, that'll do it

Rob

On 5/24/06, Robert Dober <robert.dober@gmail.com> wrote:
>
> On 5/24/06, Robert MannI <robmnl@gmail.com> wrote:
> >
> > Hello!
> >
> > I have a unit test where I need to simulate a different system time.
> >
> > Hence I need Time.now to return a different time than now, say,
> > now
> > + 1 month
> >
> > How can I do this?
> >
> > I tried aliasing Time now, but I don't know how to alias class
methods.
> >
> > class Time
> > alias_method 'self.original_now', 'self.now'
> > end
> >
> > How can I alias this --or-- is there any better way to simulate a
> > different time on calling Time.now?
> >
> >
> > Tips and ideas are greatly appreciated, Rob
>
>
> Hi
>
> class Time
> class << self
> alias_method :n, :now
> end
> end
>
> hope that helps
> Cheers
> Robert
>
>
> --
> Deux choses sont infinies : l'univers et la bêtise humaine ; en ce
> qui concerne l'univers, je n'en ai pas acquis la certitude absolue.
>
> - Albert Einstein
>
>

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

Molitor, Stephen L wrote:

I believe that you can redefine Time.now in the scope where you need
it without interfering with Test::Unit

There's only one instance of the Time class object, and any changes you
make to it are in effect 'global'.

You can use a technique called "Constant Injection" where you
temporarily change the definition of a constant within the scope of a
single class.

See http://onestepback.org/articles/depinj/classesarejustobjects.html
for an example.

This allows you to say something like:

   def test_my_class
     MyClass.use_class(:Time, MockTime) do
       mc = MyClass.new
       # Any calls to Time.now within MyClass will be routed to
MockTime.now
     end
     # Calls to Time.now are now back to normal.
   end

-- Jim Weirich

···

--
Posted via http://www.ruby-forum.com/\.

Although I do not understand it (this is not an anomaly of the universe
though), it does not look like it
please kindly look at this

------------------------------------ >8 ---------------------------------
robert@roma:~/ruby/tests$ cat test1.rb;./test1.rb
#!/usr/bin/env ruby

require 'date'

module ToBTested
        class Time
                class << self
                        def now; "right now?"; end
                end
        end

        puts "Inside module ToBTested: " << Time.now.to_s
end

puts "Outside module ToBTested: " << Time.now.to_s
Inside module ToBTested: right now?
Outside module ToBTested: Wed May 24 21:47:44 CEST 2006
--------------------------- 8<

···

On 5/24/06, Jim Weirich <jim@weirichhouse.org> wrote:

Molitor, Stephen L wrote:
>> I believe that you can redefine Time.now in the scope where you need
>> it without interfering with Test::Unit
>
> There's only one instance of the Time class object, and any changes you
> make to it are in effect 'global'.

-----------------------------------------------

*** HOWEVER ***
this theoretical possibility will probably not help the OP because
Test::Unit might not have access to the unaltered version of Time (please
note, this is ruby-talk not physics-talk) when executing in Testcase
context.
I had no time (again) going through this during working hours but if someone
would care to explain the exact location where the inconsistency occurs
withing Test::Unit I would gladly have a look.

Cheers
Robert

Very nice! If I understand correctly, I could do something like this:

class Module
  def inject_constant(constant, value)
    old_value = const_get(constant)
    const_set(constant, value)
    if block_given?
      yield
      const_set(constant, old_value)
    end
  end
end

Then in a test, I could do this:

def test_my_app
  MyApp::inject_constant(:Time, MockTime)
end

If all of my code is in the module MyApp, then all of my code uses
MockTime whenever it refers to Time. Forever in this case, which might
be fine in a test. Or I could pass a block to limit the duration. Or
use setup / teardown. If I want to be more fine grained I can just
inject into one class.

In any case, I can mock out the current time without messing up external
code, and without changing my original code. All without a fancy DI or
AOP framework. Wow!

Is this the cleanest implementation of this technique?

I went through all your DI presentation slides. Looks like it was a
fantastic presentation.

Steve

···

-----Original Message-----
From: list-bounce@example.com [mailto:list-bounce@example.com] On Behalf
Of Jim Weirich
Sent: Wednesday, May 24, 2006 12:01 PM
To: ruby-talk ML
Subject: Re: Overriding Time.now

Molitor, Stephen L wrote:

I believe that you can redefine Time.now in the scope where you need
it without interfering with Test::Unit

There's only one instance of the Time class object, and any changes
you make to it are in effect 'global'.

You can use a technique called "Constant Injection" where you
temporarily change the definition of a constant within the scope of a
single class.

See http://onestepback.org/articles/depinj/classesarejustobjects.html
for an example.

This allows you to say something like:

   def test_my_class
     MyClass.use_class(:Time, MockTime) do
       mc = MyClass.new
       # Any calls to Time.now within MyClass will be routed to
MockTime.now
     end
     # Calls to Time.now are now back to normal.
   end

-- Jim Weirich

--
Posted via http://www.ruby-forum.com/\.

You are declaring a new class named Time in your module. This may or not work for the OP.

e.g.:

% cat overriding_time.rb
class Base
   def self.something_invovling_time_now
     Time.now
   end
end

module Wrap
   class Time
     def self.now
       "Whee"
     end
   end
end

class Child < Base
   include Wrap
   puts something_invovling_time_now
   puts Time.now
end

% ruby overriding_time.rb
Wed May 24 16:42:11 EDT 2006
Whee

···

On May 24, 2006, at 3:55 PM, Robert Dober wrote:

On 5/24/06, Jim Weirich <jim@weirichhouse.org> wrote:

Molitor, Stephen L wrote:
>> I believe that you can redefine Time.now in the scope where you need
>> it without interfering with Test::Unit
>
> There's only one instance of the Time class object, and any changes you
> make to it are in effect 'global'.

Although I do not understand it (this is not an anomaly of the universe
though), it does not look like it
please kindly look at this

Correction, I should probably wrap the user code in an ensure block to
ensure that the constant gets reset:

class Module
  def inject_constant(constant, value)
    old_value = const_get(constant)
    const_set(constant, value)
    if block_given?
      begin
        yield
      ensure
        const_set(constant, old_value)
      end
    end
  end
end

Steve

···

-----Original Message-----
From: Molitor, Stephen L
Sent: Wednesday, May 24, 2006 4:21 PM
To: ruby-talk ML
Subject: Re: Overriding Time.now

Very nice! If I understand correctly, I could do something like this:

class Module
  def inject_constant(constant, value)
    old_value = const_get(constant)
    const_set(constant, value)
    if block_given?
      yield
      const_set(constant, old_value)
    end
  end
end

Then in a test, I could do this:

def test_my_app
  MyApp::inject_constant(:Time, MockTime) end

If all of my code is in the module MyApp, then all of my code uses
MockTime whenever it refers to Time. Forever in this case, which might
be fine in a test. Or I could pass a block to limit the duration. Or
use setup / teardown. If I want to be more fine grained I can just
inject into one class.

In any case, I can mock out the current time without messing up external
code, and without changing my original code. All without a fancy DI or
AOP framework. Wow!

Is this the cleanest implementation of this technique?

I went through all your DI presentation slides. Looks like it was a
fantastic presentation.

Steve

-----Original Message-----
From: list-bounce@example.com [mailto:list-bounce@example.com] On Behalf
Of Jim Weirich
Sent: Wednesday, May 24, 2006 12:01 PM
To: ruby-talk ML
Subject: Re: Overriding Time.now

Molitor, Stephen L wrote:

I believe that you can redefine Time.now in the scope where you need
it without interfering with Test::Unit

There's only one instance of the Time class object, and any changes
you make to it are in effect 'global'.

You can use a technique called "Constant Injection" where you
temporarily change the definition of a constant within the scope of a
single class.

See http://onestepback.org/articles/depinj/classesarejustobjects.html
for an example.

This allows you to say something like:

   def test_my_class
     MyClass.use_class(:Time, MockTime) do
       mc = MyClass.new
       # Any calls to Time.now within MyClass will be routed to
MockTime.now
     end
     # Calls to Time.now are now back to normal.
   end

-- Jim Weirich

--
Posted via http://www.ruby-forum.com/\.

[snip]
You are declaring a new class named Time in your module.

Of course, I completely screwed up! Sorry for the noise.

This may or

···

On 5/24/06, Logan Capaldo <logancapaldo@gmail.com> wrote:

On May 24, 2006, at 3:55 PM, Robert Dober wrote:
not work for the OP.

e.g.:

% cat overriding_time.rb
class Base
   def self.something_invovling_time_now
     Time.now
   end
end

module Wrap
   class Time
     def self.now
       "Whee"
     end
   end
end

class Child < Base
   include Wrap
   puts something_invovling_time_now
   puts Time.now
end

% ruby overriding_time.rb
Wed May 24 16:42:11 EDT 2006
Whee

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

Following up a slightly old thread here, but I've taken a hybrid approach to a couple already suggested and it seems to work well:

   class Time
     @@now = nil

     def self.now=(time)
       @@now = time
     end

     def self.forced_now
       @@now || unforced_now
     end

     class << self
       alias_method :unforced_now, :now
       alias_method :now, :forced_now
     end
   end

Then, in my test I can simply do Time.now = whatever. As long as I put a Time.now = nil in my teardown, it doesn't seem to mess up the test timings. (Note that I'm doing this in Rails, so your mileage may vary.) It's important that the Time.now = nil goes in the teardown, rather than in the test itself, to ensure that it runs even if a test fails.

Cheers,

Pete Yandell
http://9cays.com/