In his post “Redefining Constants” ( http://www.pivotalblabs.com/articles/2007/04/14/redefining-constants ), Brian Takita describes how to redefine Rails constants at test time. He points out that “it’s all dirty”, and that “…maybe the storage service can be an attribute that can be changed for individual tests.”.
In a comment, I suggested that a global configuration object would be a better approach, and here’s an example. It still uses a constant (as opposed to a global singleton object), but the constant is an object (a hash) which contain other values and objects. This avoids the need to redefine constants to use different values at test-time.
Create a sample Rails app
$ rails railsdi $ cd railsdi/ $ ls $ script/generate controller Sample $ # create development/test databases
Declare the configuration hash
First, add a constant in boot.rb. Just ignore the warning to not modify boot.rb – it’s not talking about you. Put this at the beginning, right after the section that defines RAILS_ENV
boot.rb
REGISTRY = {}
Set per-environment defaults
Set any values or objects you want in the registry:
development.rb
REGISTRY[:key] = "development_value"
test.rb
REGISTRY[:key] = "test_value"
production.rb
REGISTRY[:key] = "production_value"
Verify that the correct values are used in each environment
Make a simple controller and view to verify the values are set per-environment:
sample_controller.rb
class SampleController < ApplicationController def index @registry_value = REGISTRY[:key] end end
sample/index.rhtml
Rails Environment: <%= RAILS_ENV %> Registry Value: <%= @registry_value %>
Start up the app in development and production environments, and hit http://localhost:3000/sample
Verify that registry values can be overridden at test time
sample_controller_test.rb
def test__can_redefine_registry_value REGISTRY[:key] = 'overridden_value' get :index assert_equal 'overridden_value', assigns['registry_value'] end
Summary
I think this is a pretty good approach, and it feels a lot like testing in an app that uses a Dependency Injection/Registry architecture (in other words, simple to override anything you want). I’d be interested to hear if there are any situations that could not use this approach, and would have to fall back to defining constants in the environment files.
It would also be interesting to hear if anyone has had success integrating a Rails application with a Dependency Injection approach (using Needle or a home-grown solution).
— Chad
About the Author