Update: This has been turned into a gem for plug-and-play reuse.
In my freelance time I find myself working with an internationalized site used in over 50 countries. Of course, users of the site wanted to deal with things in a localized time zone. Adding time zone awareness brings a special angle to testing and it saddled me with some errors I had not seen before.
To start, I made use of some excellent time warp code for the unit tests I had written up. It worked beautifully. That is, it worked beautifully until I ran rake or, more specifically, rake test:functionals.
My functional tests were dying hard with these new, handy additions to test_helper.rb. From the execution of the first test, I was seeing “stack trace too deep” errors.
./test/functional/../test_helper.rb:13:in `real_now': stack level too deep (SystemStackError)
from ./test/functional/../test_helper.rb:13:in `real_now'
from ./test/functional/cms/../../test_helper.rb:13:in `now'
from /usr/local/lib/ruby/1.8/logger.rb:327:in `add'
from /usr/local/lib/ruby/1.8/logger.rb:348:in `debug'
from /Users/bjhess/Sites/iridesco/afs/trunk/config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:114:in `default_helper_module!'
from /Users/bjhess/Sites/iridesco/afs/trunk/config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:124:in `send'
from /Users/bjhess/Sites/iridesco/afs/trunk/config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:124:in `inherited'
from /Users/bjhess/Sites/iridesco/afs/trunk/config/../app/controllers/cms/email_controller.rb:1
... 9 levels...
from /Users/bjhess/Sites/iridesco/afs/trunk/config/../vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:489:in `load'
from /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake_test_loader.rb:5
from /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake_test_loader.rb:5:in `each'
from /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake_test_loader.rb:5
rake aborted!
Command failed with status (1): [/usr/local/bin/ruby -Ilib:test "/usr/local...]
The specific bit of code appeared to be the real_now call on the line real_now - testing_offset:
alias_method :real_now, :now
def now
real_now - testing_offset
end
alias_method :new, :now
My workaround was to move all of the time warp code into its own time_helper.rb file.
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
class Time #:nodoc:
class <<self
attr_accessor :testing_offset
alias_method :real_now, :now
def now
real_now - testing_offset
end
alias_method :new, :now
end
end
Time.testing_offset = 0
class Test::Unit::TestCase
def pretend_now_is(time)
begin
Time.testing_offset = Time.now - time
yield
ensure
Time.testing_offset = 0
end
end
end
Then I simply included the time_helper file along with test_helper in any test that required time warping:
require File.dirname(__FILE__) + '/../test_helper'
require File.dirname(__FILE__) + '/../time_helper'
class EventTest < Test::Unit::TestCase
. . .
end
This worked beautifully. Unfortunately I’m at a loss as to why the initial setup had problems and I really wish I did know why. I don’t like being in the dark on problems.
