Zamrożenie czasu przy pomocy Time.is

Czasami podczas pisania unit testów nasz kod ustawia atrybut obiektu na obecny czas przy pomocy Time.now. Mamy problem jeśli chcemy sprawdzić czy rzeczywiście atrybut został ustawiony na obecny czas Time.now, np.

[code=ruby]describe Post do

it “should set created_at to current time” do
post = Post.new
post.save
post.created_at.should == Time.now
end
end[/code]
Powyższy kod nie przejdzie testów ponieważ czas w momencie ustawienia atrybutu created_at będzie różny od Time.now w momencie sprawdzenia post.created_at.should == Time.now (szczególnie będzie to widoczne na wolniejszych komputerach kiedy pomiędzy ustawieniem atrybutu a sprawdzeniem występuje widoczna różnica czasu)

Z pomocą przychodzi poniższa metoda Time.is dzięki której możemy “zamrozić” czas w obrębie wykonywania bloku:

[code=ruby]class Time

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

useful for unit testing

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

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[/code]
Znalezione tutaj