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/\.